1~10
BUUCTF(1~10题wp)
1.test_your_nc
运行,直接利用system函数“cat flag”即可。
2.rip
(1)解题思路
例行检查后,用 F5 查看伪代码
发现gets危险输入
看到fun函数调用了“system”,找到fun的地址 0x401186
则利用gets溢出返回到fun函数地址即可
(2)Payload
1 |
|
PS:有时栈的大小未知,需要利用GDB调试出偏移地址的大小。
3.warmup_csaw_2016
(1)解题思路
例行检查,用 F5 查看伪代码
发现flag提示
找到调用system的函数地址:0x400611
(2)GDB调试找偏移地址
1.打断点
2.先 r 一下
3.利用cyclic函数生成构造的字符串队列,作为程序的输入。
4.利用”cyclic -l 中断字符串“计算得出偏移:
PS:由于char构造的字符数组在实际分配内存时会多占用一个字节的内存。多出来的一个字节用来存储”\0”用来表示字符串的结束。
故所得偏移地址为64字节,即0x40为栈的大小。
(3)Payload
1 |
|
4.ciscn_2019_n_1
(1)解题思路
例行检查,用 F5 查看伪代码
进入fun( )函数中
发现需要利用gets函数溢出到v2的地址,并修改v2的值为11.28125,从而返回system函数拿到flag。
找到v2和v1的地址
偏移地址=0x30-0x04=0x2c
11.28125=0x41348000
(2)Payload
1 |
|
5.pwn1_sctf_2016
(1)解题思路
例行检查后,用 F5 查看伪代码
发现只有一个“vuln()”函数,点进去
在网上搜索大佬的解释,发现fgets是我们的输入点,但是它只读入了32(=0x20)长度的数据,小于0x3c,没有办法造成溢出,但是这个程序有点意思的地方就在于会将一个字节的“I”替换成三个字节的“you”
那么思路来了,我们输入20字节的 “I” ,经过第19行的replace函数后会变成60字节的 “you” ,这样就可以进行溢出了,之后覆盖ebp,覆盖返回地址为输出flag的函数地址,就可以完成利用!
然后用 Shift+F12 来查看程序里的字符串
发现有明显的flag提示
找到调用“system”函数的地址
get_flag函数
(2)Payload
1 |
|
6.jarvisoj_level0
(1)解题思路
例行检查后,用 F5 查看伪代码
可以利用read函数制造栈溢出。
在函数列表中发现调用system函数的提示
果然
记录该函数地址:0x400596
GDB调试出偏移地址为136字节,即0x88为栈的大小。
(2)Payload
1 |
|
7.[第五空间2019 决赛]PWN5 (Canary绕过)
(1)分析
例行检查后,用 F5 查看伪代码
根据网上的解释,函数的功能是读入一个4位的随机密码,再将我们输入的密码与随机生成数比较,相同就执行system。
这里面的printf()存在格式化字符串漏洞
printf()格式化字符串漏洞
利用思路
1.利用 “AAAA %08x %08x %8x %08x %08x %08x %08x………… “,这样的字符串来找到我们输入的参数在函数栈上的位置,即首地址偏移或者偏移量
2.假设是在栈上第n位,那么可以利用 %n$ 定位到参数在栈上的位置
3.利用%n来修改参数里的内容,我们不知道读入的随机数是多少,那么我们将它改成我们写入的数据
首先我们要定位到我们输入的字符串在栈上的位置。
我们输入的参数是在栈上的第10个,后面可以直接利用 %10$ 定位到这个位置。
随机生成函数的位置是0x804c044开始的,长度为4字节,依次+1即可。
所以可以用%10$,%11$,%12$,%13$去定位到这4个地址,再用%n修改这这个地址里的内容
绕过Canary保护机制
先用GDB运行一下
发现”AAAA“的ASCII编码“41414141”离首字节有10个字符串,故输入的字符定位在函数栈上的第10个位置,后面可以直接利用 %10$ 定位到这个位置。
从主函数中能看到随机生成函数的位置是0x804C044开始的,长度为4字节,依次+1即可。
所以可以用%10$,%11$,%12$,%13$
去定位到这4个地址,再用%n修改这这个地址里的内容,因此构造payload
(2)Payload
1 |
|
payload分析:
payload = p32(0x804c044) + p32(0x804c045) + p32(0x804c046) + p32(0x804c047)
:构造一个字符串,其中包含4个32位整数,分别是0x804c044
、0x804c045
、0x804c046
和0x804c047
。这些整数是用于指定格式化字符串漏洞中待写入的地址。
payload += b'%10$n%11$n%12$n%13$n'
:在已构造的字符串后追加一个格式化字符串,其中使用了格式化字符串的特殊格式%n
。%n
的作用是将前面的字符数(即已输出的字符数)写入到对应的地址中。具体来说,%10$n
表示将已输出的字符数写入到第10个参数所指向的地址中,%11$n
表示将已输出的字符数写入到第11个参数所指向的地址中,以此类推。利用格式化字符串漏洞,将已输出的字符数写入到指定的地址中。通过在payload中指定不同的地址,可以将相应的值写入到这些地址中。根据payload中的内容,第10个参数的地址将被写入
0x804c044
,第11个参数的地址将被写入0x804c045
,以此类推。这样,当程序执行到这个payload时,它会将已输出的字符数写入到指定的地址中,实现对这些地址的写入操作从而覆盖原有的canary保护。
8.ciscn_2019_c_1 (libc泄露地址)
(1)分析
例行检查
开启了栈不可执行,因此shellcode方法失效
用 F5 查看伪代码
尝试先在GDB中运行一下,发现这是一个输入1/2/3来进入以下三个函数的程序
进入这三个函数查看,在encrypt函数中发现gets,因此估计是一道ret2libc的题目,由于这是64位程序,寻找”pop、rdi、ret“就行
使用ROPgadget寻找
(2)Payload
1 |
|
脚本分析:
puts_plt = elf.plt["puts"]
:从ELF对象中获取puts
函数的PLT地址。
puts_got = elf.got["puts"]
:从ELF对象中获取puts
函数的GOT地址。
pop_rdi_ret = 0x400c83
:设置pop rdi; ret
指令序列的地址,该指令用于将参数加载到RDI寄存器中。
ret = 0x4006b9
:设置ret
指令的地址,该指令用于返回函数调用。
encrypt_addr = elf.symbols["encrypt"]
:从ELF对象中获取encrypt
函数的地址。
main_addr = elf.symbols['main']
:从ELF对象中获取main
函数的地址。
payload = b'a' * (0x50 + 0x08) + p64(pop_rdi_ret) + p64(puts_got) + p64(puts_plt) + p64(encrypt_addr)
:构造payload用于触发漏洞。payload包括一些填充数据(b'a' * (0x50 + 0x08)
)和ROP链。ROP链的作用是构造栈上的一系列指令序列,以实现漏洞利用的目的。具体来说,这个ROP链的作用是调用puts(puts_got)
,将puts
函数的真实地址泄露出来,以便后续计算libc基址。
io.sendlineafter("Input your choice!\n",str(1))
:发送字符串”1”给远程服务,用于选择相应的功能。
io.sendlineafter("Input your Plaintext to be encrypted\n",payload)
:发送payload给远程服务,用于触发漏洞。
io.recvuntil(b"Ciphertext\n")
:接收远程服务发送的数据,直到遇到字符串”Ciphertext\n”。
io.recvuntil(b"\n")
:接收远程服务发送的数据,直到遇到换行符。
puts_addr = u64(io.recvline().strip().ljust(8,b'\0'))
:接收远程服务发送的数据,将其转换为64位整数,即puts
函数的真实地址。
libc = LibcSearcher("puts",puts_addr)
:创建LibcSearcher对象,以便后续通过puts
函数地址查找libc基址和其他函数地址。
libcbase = puts_addr - libc.dump('puts')
:计算libc基址。
system_addr = libcbase + libc.dump('system')
:计算system
函数的地址。
str_bin_sh = libcbase + libc.dump('str_bin_sh')
:计算"/bin/sh"
字符串的地址。
payload = b'a' * (0x50 + 0x08) + p64(ret) + p64(pop_rdi_ret) + p64(str_bin_sh) + p64(system_addr) + p64(main_addr)
:构造新的payload,其中包括填充数据、ROP链和/bin/sh
字符串地址。这个ROP链的作用是调用system("/bin/sh")
函数。
(3)总结
通过漏洞泄露puts
函数的真实地址,并计算出libc基址。然后,构造合适的ROP链来调用system
函数,并传递"/bin/sh"
字符串作为参数,从而获取shell权限。
- 找到函数地址:首先,使用
ELF
模块获取目标二进制文件中函数的地址。在脚本中,通过elf.plt
和elf.got
来获取puts
函数的plt
和got
表项的地址,以及encrypt
和main
函数的地址。 - 构造漏洞触发payload:在脚本中,通过构造一系列的字节串来构造payload。首先,用
b'a' * (0x50 + 0x08)
填充到缓冲区,然后利用pop_rdi_ret
和puts_got
地址,以及puts_plt
函数的地址,构造ROP链。最后,使用encrypt
函数的地址,将payload发送给目标程序。 - 泄露libc基址和获取系统函数地址:通过接收目标程序返回的数据,获取泄露的
puts
函数的地址。然后,使用LibcSearcher
模块根据泄露的puts
函数地址来搜索libc库,并计算出libc基址。最后,通过libc基址计算出system
函数的地址和/bin/sh
字符串的地址。 - 构造第二个payload:使用泄露的libc基址、
ret
指令地址、pop_rdi_ret
指令地址和/bin/sh
字符串地址,构造第二个payload。ROP链的顺序为:ret
、pop_rdi_ret
、/bin/sh
、system
、main
。 - 发送第二个payload获取shell:将第二个payload发送给目标程序,成功获取到shell。
9.ciscn_2019_c_8
(1)解题思路
例行检查,发现保护全开了
进入IDA看一下
发现只需要让var[13] = 17 就可以调用system函数了
这里需要注意:
==qword全称是Quad Word。2个字节就是1个Word(1个字,16位),q就是英文quad-这个词根(意思是4)的首字母,所以它自然是word(2字节,0~2^16-1)的四倍,8字节==
所以代码的意思是要将var[13]之后的8个字节的数据赋值为17。
(2)payload
1 |
|
10.jarvisoj_level2
(1)解题思路
例行检查
IDA中函数很简单,
开了NX就不能用shellcode了,另外程序没有开canary(栈溢出检测)、内存地址随机化(PIE),所以用基本的ROP
找system和\bin\sh地址
system_addr=0x8048320
shell_addr=0x804a024
buf的大小是0x88,读入的数据大小是0x100,可以溢出0x78个字节
(2)payload
1 |
|