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 | |