프로그램 분석




이번 문제는 바이너리 없이 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