(置顶)pwncollege部分通关记录
指 https://dojo.pwn.college/challenges
按照网站要求,这里只提供思路和前两题的exploit。
heap
babyheap1.0~2.1——uaf
1 | def exploit(): |
babyheap3.0~3.1——uaf2.0
注意tcache是LIFO结构
babyheap4.0&4.1——tcache double free
第一次独立写出堆题,虽然是最简单的那种tcache double free
。
babyheap5.0&5.1——unsorted bin attack
libc 2.23->libc 2.31
通过耗尽所有的tcache来触发small bin和unsorted bin,进而修改chunk。
babyheap6.0&6.1——tcache poisoning
简单的tcache poisoning
https://wargames.ret2.systems/level/how2heap_tcache_poisoning_2.31
babyheap7.0&7.1——tcache poisoning2.0
由于flag不会变化,secret后半部分,只需将sec_addr+=8,重新运行即可。
babyheap8.0&8.1——brute force
通过先前的方法可以泄露出secret的后12位,前4位可以通过暴力枚举实现。
脚本跑了一节课才跑出来。
babyheap9.0——tcache double free
由于允许uaf,第一次free过后将next指针置0,即可double free。
此时如果将next改成0x42b321
就可在给出的堆信息中看到key。
babyheap9.1——tcache double free | perthread corruption
接着上一关的步骤,接着malloc两次,虽然题目禁止你读取key附近的指针,但malloc操作还是进行了。
由于tcache
的链表特性,addr+8
处会被清零。再进行一次这样的操作后,可以输入16个\0
通过验证。
通过修改地址到perthread struct读取在链表头的8字节key理论上可行,就没试了。
babyheap10.0&10.1——heap on stack
给出了栈地址与elf地址,因此直接把堆放到栈上,修改retn地址即可。
babyheap11.0&11.1——free_hook+arbitary read
由于不知道elf地址和栈地址,首先我覆盖free_hook
(注意写free_hook的时候size位最好是\x7f
)成为system_plt
拿到了shell,但是并没有权限。
然后发现执行echo函数后会多开辟一个堆空间,里面有elf与stack相关的地址,而且echo函数没有限制偏移大小,因此可以拿到这些地址。
由于我已经可以写free_hook
,直接将free_hook
覆盖成win
即可。
babyheap12.0&12.1——modify size
由于tcache
的机制,修改栈上堆的size
即可绕过合法性检测。
babyheap13.0——tcache double free
类似于babyheap9.1的做法,分配到sec
附近,然后输入一堆\0
覆盖key
。
babyheap13.1——modify size
由于sec与堆的偏移不超过一个字节,修改栈上堆的size
之后,使用malloc
分配一个稍微大点的堆填充数据即可。
babyheap14.0&14.1——modify size+leak elf&canary
在level13的基础上,用echo
泄露elf
地址与canary
地址,然后在堆上进行栈溢出。
对于14.1,注意\x09
不可输入,建议换一个靠后的地址。
babyheap15.0&15.1——leak elf&stack+unlink
这个题有点tricky,我把elf、stack、libc、heap泄露完了才发现uaf已经没了。
任意写的方式除了double free就是unlink了,我懒得去想多么巧妙的堆风水,干脆直接unlink结束战斗。
kernel
babykernel1.0~6.1——basic definition
参照这篇博客:https://www.cnblogs.com/crybaby/p/14431651.html
kernel shellcode着实有点麻人。
注:如何查看有没有kaslr?
进入kernel后,
demsg
查看第二行最后有没有nokaslr
babykernel7.0~7.1——struct&debug
需要传入一个类似于这样的结构体:
1 | struct shellcode{ |
注意以下几点:
- shellcode必须包含ret语句(ret2usr)。
- shellcode_addr可以通过动调得到,位置固定。
babykernel8.0~8.1——shellcode in shellcode
一句话——在shellcode里写shellcode
第一次进内核来一遍commit_creds(prepare_kernel_cred(0))
,ret2usr
后变成root
shell。再进入一次run_cmd /bin/chmod 777 /flag
即可修改flag权限。(注意在内核态里起shell没有任何作用)
babykernel9.0~9.1——run_cmd
直接把printk
指针改为run_cmd
,然后rdi
是输入处,写入/bin/chmod 777 /flag
即可。
babykernel10.0——kaslr leak
注意kaslr只有在kernel重启之后才会重新随机,所以重新运行程序,原有的kernel函数地址不会变。
与userland的aslr类似,kaslr的低5位都是固定的。写入256字节使得printk
的地址被泄露,从而找到run_cmd
的地址。
babykernel10.1——partial overwrite
由于该驱动不会打印自己的输入,这里采取重写printk
的后3字节,也就是得爆破run_cmd
的倒数第六位。
babykernel11.0~12.1——memory scanning
程序将flag加载到内存里,然后删掉了flag文件,因此flag只能在内存里面找。
通过discord的spoiler可以得知应该从0xffff888000000000
开始扫内存(即宏phys_to_virt(0)
的值,也是源码中__PAGE_OFFSET_BASE_L4
一行的值),然后dmesg
找一下flag即可。
注意以下几点:
- 如果用这个网站将汇编转成字节码,务必把字节码转成汇编验证一下是否漏掉了指令。
- 为了减少输出,建议将地址的值与
pwn.coll
(或类似的64位字符串)比较一下再打印到控制台。 - python很耗费内存,可能起一遍python,flag那部分的内存就被重新分配了。所以建议把shellcode输出到文件再进行文件流输入。