매번 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

Heap에서 발생할 수 있는 취약점에 대해 간단하게 내맘대로 정리해보자


1. Heap overflow

-    Heap 영역에 할당된 공간보다 큰 사이즈를 입력받아 발생할 수 있음

-    발생 예제

buf = malloc(100)

...

int size;

scanf("%d", &size);

read(0, buf, size);


-    활용방법

다음 chunk의 헤더 부분을 덮을 수 있는 경우, prev, next pointer를 조작해 free 시 임의 메모리 쓰기 발생 시킬 수 있음

(free 메커니즘에 의존, 제한적)


2.  Double free 

- heap overflow와 나누기 이상하기는 하지만 활용에 있어서 다르기 때문에 나눔

- 기본적으로 heap overflow 취약점을 가져야 함

- 활용방법

Heap chunk 헤더 내의 flag(정확히 표현하면 현재 chunk size의 하위 3비트) 값을 조작함으로써 할당된 chunk를 free된 것으로 인식하게 함

조작된 chunk 이전의 chunk가 free될 시 병합과정에서 위 1.과 유사하게 임의 메모리 쓰기 가능



3. fastbin dup into stack

-    참고(http://www.blackhat.com/presentations/bh-usa-07/Ferguson/Whitepaper/bh-usa-07-ferguson-WP.pdf)

-    allocation된 chunk를 free하면 재사용을 위해 free된 chunk를 linked list로 관리하고 이를 bin이라고 함

-    chunk의 사이즈가 작을 경우(기본 최대 60바이트, 설정하면 최대 80바이트) fastbin 이라는 free list를 통해 관리되며 다음과 같은 특징을 가짐

sorting이 되지 않음

singly linked list

LIFO

-    아무튼 작은 사이즈의 chunk를 할당하고 free 하는 경우



4. The house of force

-    Heap overflow를 이용해 top chunk를 덮음

-    이를 통해 할당할 수 있는 chunk size의 제한이 없어짐


5. Use after free(UAF)

-    free된 메모리 공간의 포인터에 접근할 수 있는 경우


나중에 내용 더 추가하자

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

pwnable.kr 문제풀이 현황  (0) 2018.05.12


pwnable.kr AEG 문제를 보던 중 푸는데에 ANGR을 사용해보면 좋을 것 같아 이 참에 찾아보았다.

구글링 등 예제 코드를 보고 내가 대충 작성한 코드는 다음과 같았는데

(문제 바이너리를 local 로 다운로드 받았다고 치고 시작)


mine.py 

 def main():

        proj = angr.Project('newbin0', load_options={"auto_load_libs": False})


        input_size = 0x60

        argv1 = claripy.BVS("argv1",input_size * 8)


        init = proj.factory.entry_state(args=["./newbin0", argv1])

        init.libc.buf_symbolic_bytes=input_size + 1

        al = [0x947C86,0x947976,0x9478FB,0x947889,0x947809,0x94778C,0x94770C,0x94768C,0x947610,0x9475A8,0x94752B,0x9474A9,0x94742C,0x9473B3,0x947337,0x9472BB,0x94723B]


        for byte in argv1.chop(8):

                init.add_constraints(byte >= '0')

                init.add_constraints(byte <= 'Z')

                init.add_constraints(byte != '\x3a')

                init.add_constraints(byte != '\x3b')

                init.add_constraints(byte != '\x3c')

                init.add_constraints(byte != '\x3d')

                init.add_constraints(byte != '\x3e')

                init.add_constraints(byte != '\x3f')

                init.add_constraints(byte != '\x40')


        init_path = proj.factory.path(init)

        path_group = proj.factory.path_group(init)

        path_group.explore(find=FIND_ADDR, avoid=al)


        found = path_group.found[0]

        solution = found.state.se.any_str(argv1)

        return solution



위와 같이 코드를 작성하고 실행할 경우 문제는 원하는 방향으로 풀리고 Hex 값을 return 해주지만 실행시간이 약 60초 걸렸다.

문제에서 주어진 시간은 10초로 angr 돌리는데에만 터무니없이 긴 시간이 걸렸음.

시간을 줄이기 위해 avoid 조건을 이용해 이것 저것 넣어봤는데 효과는 미비했다.


구글링 중 github에 aeg 문제풀이 코드가 나와있는 것을 찾았고 여기서 angr 부분만 참고했다.

(출처 : https://github.com/rot256/Wargames/blob/master/pwnable/aeg/attack.py)

원본 코드는 위 URL에서 확인할 수 있으며 밑에는 테스트에 필요한 코드만 추출, 조작함


attack.py

# Create symbolic buffer

p = angr.Project(tar)

buf = claripy.BVS("buf",48*8)

start_state = p.factory.blank_state(addr=0x2233b96)

start_state.memory.store(0x2436160, buf)


# Setup a stack frame

start_state.regs.rbp = start_state.regs.rsp

start_state.regs.rsp = start_state.regs.rsp - 0x50

start_state.memory.store(start_state.regs.rsp, start_state.se.BVV(0, 8*0x32))


# Setup stepper

pg = p.factory.path_group(start_state)

def step_func(pg):

    pg.drop(filter_func = lambda path: path.addr == 0x2233bbd)

    pg.stash(filter_func = lambda path: path.addr == 0x4006e0, from_stash='active', to_stash='found')

    return pg

pg.step(step_func = step_func, until = lambda pg: len(pg.found) > 0)

f = pr.found[0]

cert = f.state.se.any_str(buf)

print cert.encode('hex')


위 스크립트 실행 시 약 6-7s 정도 시간 소요로 답을 구할 수 있었다.


결국 차이점은

1) 적절한 바이너리의 start state 설정

2) avoid 조건

으로 필요한 연산만 하도록해 state를 줄여줄 수 있는 것으로 보인다.


조금 더 공부해봅시다.

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

[pwnable.kr] dos4fun - 444pt  (5) 2018.03.14
[pwnable.kr] sudoku - 111pt  (0) 2018.02.19
[pwnable.kr] AEG - 550pt  (0) 2018.02.11
[pwnable.kr] maze - 150pt  (0) 2017.12.23

최근 pwnable.kr Grotesque 문제들이 너무 어려워서 스트레스... 였는데 간만에 재밌게 풀었습니다.


취약점은 리버싱해보면 비교적 쉽게 발견할 수 있고, 바이너리 내에 system(/bin/sh) 함수도 있으니 취약점까지 가는 길만 찾으면 되겠습니다

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

[pwnable.kr] dos4fun - 444pt  (5) 2018.03.14
[pwnable.kr] sudoku - 111pt  (0) 2018.02.19
[pwnable.kr] AEG - 550pt  (0) 2018.02.11
ANGR로 AEG를 풀어보자  (0) 2018.01.25
프로그램 분석




이번 문제는 바이너리 없이 client, host 에서 돌고 있는 파이썬 스크립트를 주어지는데
주어진 스크립트에는 중요 변수 내용(iv, key, cookie) 값이 없는 상태이다.



주요 코드를 살펴보면  client에선 ID, PW, COOKIE 값을 (ID-PW-COOKIE)를 암호화한 값을 전송하며
서버에선 이 값을 복호화해 - 를 기준으로 split해 값을 판별하는 것을 알 수 있다.




취약점 탐색

이번 문제를 보면서 역시나 시스템적인 취약점이 있지 않을까? 하면서 여기 저기 값을 "A"*100.... 넣어봤는데 취약점은 발동하지 않았다.

문제의 의도대로 AES - CBC 암호화에 대해 알아야 풀 수 있는 것 같아 암호화 알고리즘에 대해 공부했다.
참고 자료에서 보면 자세히 알 수 있지만 간단히 말하자면
plain text를 block size 에 따라 나눠 암호화하고, plain text (xor) initial vector 한 값을 암호화해 나온 암호화 block 값을 다음 암호화에 사용하는 게 핵심적인 내용이다.

여기서 중요한 것은 plain text를 block size로 나눠 암호화 하며, 첫 번째 block은 initial vector 값에 의존해 암호화되어 결과값이 나온다는 것 2가지이다.



위 코드에서 보듯, block size는 16byte 이므로 16byte씩 끊어서 암호화를 진행하게 된다

이 때 위의 그림을 보면 id, pw, cookie 값을 - 문자를 기준으로 split 하는 것이 중요한 취약점이 될 수 있다.

사용자의 입력을 받는 id, pw 같은 경우 - 문자가 들어갈 수 있으므로 (입력 가능한 문자 아래 그림 참조)




사용자가 만약 id를 a-b-c- 로 입력 시 프로그램은 a를 ID, b를 PW, C를 COOKIE 값으로 판별하게 된다.

즉 사용자의 의도대로 ID, PW, COOKIE 값을 변조할 수 있는 것인데 서버 프로그램의 코드를 살펴보면



사용자가 전송한 COOKIE값이 일치하지 않을 경우 0을 return해 인증되지 않은 사용자라는 출력을 해주고 프로그램은 종료된다.
결국 COOKIE 값을 맞춘 후, hash값만 일치시키면 admin 사용자로 인증할 수 있게 된다.



COOKIE 값을 구하기 위한 Idea 고찰

cookie값은 어떤 값, 방식을 통해 구할수 있을까? 고민하다가 

우선 id, pw, cookie 값이 - 로 구분되는 것첫 번째 암호화된 block의 변수는 plain block1 값과 iv 값 두 가지 인것을 이용하기로 했다.

즉 iv의 값이 고정일 경우 plain block1 의 값이 변해야 encyrpted block1 의 값이 변하는 것이므로 다음과 같은 아이디어를 생각했다.


ID : '-' * 12, PW : '-' 를 입력한다면 ?

암호화 되기 전 평문은  ---------------COOKIEVALUE.... 이런식으로 구성 될텐데 이 때 블럭 사이즈가 16 이므로 

---------------C |  OOKIEVALUE...... | ......
   block 1.              block 2.             block 3 ....

위 평문을 암호화한 암호문의 첫번째 블락의 값을 구하면 ---------------C, 즉 쿠키의 첫번째 글자를 포함한 암호화 값을 알 수 있다.



또 우리는 ID, PW에 '-' 문자를 포함할 수 있으므로 

ID : '-'*15 + ?      , PW : anything

위 물음표 자리에 문자열을 하나씩 대입해 나오는 암호문의 첫번째 블락 값을 위 쿠키의 첫번째 글자를 포함한 암호화 값비교하면

쿠키의 첫번째 글자의 값을 알 수 있다.

이와 같이 한글자씩 쿠키의 값을 알아낼 수 있다.



COOKIE 값 구하는 코드

코드 돌리면서도 계속 헷갈려서 자동화는 안하고 손으로 맞춰보면서 돌렸다.
한마디로 발로 짜서 개판인 코드 허허...

from pwn import *


context(arch = 'amd64', os = 'linux')

local=False


# first  

p = remote("pwnable.kr", 9006)


print p.recvuntil('ID\n')

p.sendline('-'*12)

print p.recvuntil('PW\n')

p.sendline('-')

data = p.recvuntil('user\n')

enc = data[data.index('(')+1:data.index(')')]

print len(enc)


enc = enc[0:32]

print enc

print len(enc)


# brute

for i in '1234567890abcdefghijklmnopqrstuvwxyz-_ABCDEFGHIJKLMNOPQRSTUVWXYZ' :

        p = remote("pwnable.kr", 9006)

        p.recvuntil('ID\n')

        p.sendline('-'*15+i)

        p.recvuntil('PW\n')

        p.sendline('-')

        data = p.recvuntil('user\n')

        try_ = data[data.index('(')+1:data.index(')')]

        try_ = try_[0:32]

        if enc == try_ :

                print "FIND!! first one is " + i

                break

 

 




Flag 얻기

cookie값을 알았으므로 나머지는 간단히 처리할 수 있다.



위 코드를 보면 ID가 admin 이며, PW의 hash 값이 맞는 경우 서버로부터 2를 return 받고 flag 값을 알 수 있다. 

다음과 같이 'admin' + cookie 값의 hash 값을 구해서

print hashlib.sha256("admin"+COOKIE_VALUE).hexdigest()



ID :  admin-HASH_VALUE-COOKIE_VALUE
PW : anything

을 전송하면 정상적으로 flag 값을 확인 할 수 있다.








===============================================================================================



참고자료 1. (출처:https://wikidocs.net/64)


3.5. 축약함수(Lambda)

오늘은 람다 형식과 그것을 이용하는 여러가지 함수들에 대해서 알아보겠습니다. 당장 완벽하게 소화하실 필요는 없을 것 같구요, 가벼운 마음으로 이런 것이 있다는 정도만 아셔도 되지 않을까 합니다. 람다 형식은 인공지능 분야나 AutoCAD라는 설계 프로그램에서 쓰이는 Lisp 언어에서 물려받았다고 하는데요, 함수를 딱 한 줄만으로 만들게 해주는 훌륭한 녀석입니다. 사용할 때는 아래와 같이 써주면 되지요.

lambda 인자 : 표현식

다음은 두 수를 더하는 함수입니다.

>>> def hap(x, y):
...   return x + y
...
>>> hap(10, 20)
30

이것을 람다 형식으로는 어떻게 표현할까요?

>>> (lambda x,y: x + y)(10, 20)
30





참고자료 2. (https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher_Block_Chaining_.28CBC.29)


암호 블록 체인 방식 (CBC)[편집]

암호 블록 체인 (cipher-block chaining, CBC) 방식은 1976년 IBM에 의해 개발되었다.[4] 각 블록은 암호화되기 전에 이전 블록의 암호화 결과와 XOR되며, 첫 블록의 경우에는 초기화 벡터가 사용된다. 초기화 벡터가 같은 경우 출력 결과가 항상 같기 때문에, 매 암호화마다 다른 초기화 벡터를 사용해야 한다.

Cbc encryption.png

Cbc decryption.png

CBC 방식은 현재 널리 사용되는 운용 방식 중 하나이다. CBC는 암호화 입력 값이 이전 결과에 의존하기 때문에 병렬화가 불가능하지만, 복호화의 경우 각 블록을 복호화한 다음 이전 암호화 블록과 XOR하여 복구할 수 있기 때문에 병렬화가 가능하다.



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

[pwnable.kr] loveletter - 50pt  (0) 2018.09.07
[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