buu093-wustctf2020_easyfast
Ubuntu 16.04下的简单堆题,使用fastbin直接UAF,分配到关键位置,注意前面有一个0x50表示chunk的大小,如果这个值不存在,那么这里是无法分配chunk的。
1 | from pwn import * |
buu094-ciscn_2019_es_1
这道题虽然说的是“hate libc 2.29”,但实际上最后发现用的还是glibc 2.27-3ubuntu1版本,也就是能够double free的版本。本题想要获取libc地址很简单,因为free之后地址还在,只要add一个大于0x400的chunk,释放后再show一下即可获取。然后double free一个小chunk,以将chunk分配到__free_hook。
1 | from pwn import * |
buu095-wdb2018_guess
这道题的解法需要使用glibc 2.23下的__stack_chk_fail
函数。在2.23中,__stack_chk_fail
的函数定义如下:
1 | void |
这是函数__stack_chk_fail
直接调用的函数,可以看到这里会打印出argv[0]
的内容,这个值在调试过程中会保存到r13寄存器的位置。且一般在栈的顶部位置。这个地址与我们通过gets写入字符串的地址的偏移是固定的,因此第一次我们可以通过将这个值修改为got表地址,来获取到libc的加载地址;第二次我们将其修改为environ
变量的值,这个变量位于libc中,保存着栈地址;在获取了栈地址之后,第三次我们就可以将其修改为flag的内容,然后就可以输出了。
1 | from pwn import * |
buu096-gyctf_2020_some_thing_exceting
这道题做的时候大意了,做着做着给flag已经被读到内存这件事给忘了……
在flag已经读入内存的情况下,这道题是很简单的,就是一个基础的堆排布,让0x10的header分配到可以写的buffer里面,直接修改指针的值然后show就行了。
如果这道题没有flag在内存中,首先就应该通过上面的这种方法获取libc基址,然后使用fastbin attack,用一次double free分配到__malloc_hook
,注意修改指针的值应该是__malloc_hook - 0x23
,原因参见我的这篇文章:传送门
注意这里不能分配到__free_hook
,因为fastbin分配之前会检查size字段,而__free_hook
前面并不存在有效的size字段。然后将__malloc_hook
改成one_gadget,可惜测试完发现4个one_gadget都不行,于是开始怀疑人生,然后突然就意识到flag在内存中本来就有……
下面的代码注释掉的部分就是不存在flag时的利用方式。
1 | from pwn import * |
buu097-axb_2019_heap
这题的漏洞在于输入的时候会溢出1个字节,因此自然就可以想到使用unlink的方法来做。但这道题有一个很坑的点就是不能用LibcSearcher,虽然它能给你查到2个libc,但是无论你用哪个,远程都打不通,报错,但是用buuoj提供的64位的2.23 glibc就行,这个点坑了我好几个小时才发现。
1 | from pwn import * |
buu098-oneshot_tjctf_2016
第一次输出got表地址,然后获取libc地址,跳转到one_gadget即可。
1 | from pwn import * |
buu099-护网杯_2018_gettingstart
1 | from pwn import * |
buu100-wustctf2020_number_game
计算机组成原理的知识……对于32位整数而言,只有0x80000000这个数(-2147483648)取相反数的值为2147483648,还是0x80000000,所以表示的数不变。输入这个数就行了。
buu101-zctf2016_note2
这道题提供了4个选项:增加、删除、修改、查看。其中修改能够提供2种选项——追加和覆写。修改部分的代码如下:
1 | void __fastcall edit() |
注意其中的strncat
函数,其第3个参数是字符串拼接之后的最大长度,虽然这里传的是最大的无符号整数,但是并不意味着这里可以溢出,因为前面还有一个v0[size - strlen(dest) + 14] = 0;
将要追加的内容截断了,因此漏洞点不在这里。
经过测试发现,在glibc 2.23版本中,malloc(0)
会创建一个大小为0x20的chunk,此时我们的重点就放在了输入的函数中:
1 | unsigned __int64 __fastcall input(char *buffer, __int64 maxsize, char endchar) |
注意循环是for ( i = 0LL; maxsize - 1 > i; ++i )
,查看汇编:
1 | .text:0000000000400A28 loc_400A28: ; CODE XREF: input+1D↑j |
这里是ja指令,因此是无符号的比较,但如果传入的size为0的话,那么这里就相当于是溢出任意多个字节。
既然有这样一个漏洞,在2.23环境很容易想到unlink,毕竟本题elf没加PIE,我们知道堆地址是保存在什么地方的,因此unlink最方便。
我的做法是覆盖atoi的got表地址为system,然后在输出菜单之后直接输入/bin/sh
即可。
1 | from pwn import * |