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

+ Recent posts