ASIS CTF Quals 2018 Writeup
はじめに
いつもと違うチームでASIS CTF 2018に参加しました。全然解けなくて駄目。
warmup(Reverse, 27pt)
- Cのソースファイルを与えられる.
#define q (2+M/M) #define v (q/q) #define ef ((v+q)/2) #define f (q-v-ef) #define k (8-ef) struct b{int64_t y[13];}S;int m=1811939329,N=1,t[1<<26]={2},a,*p,i,e=73421233,s,c,U=1;g(d,h){for(i=s;i<1<<25;i*=2)d=d*1LL*d%m;for(p=t;p<t+N;p+=s)for(i=s,c=1;i;i--)a=p[s]*(h?c:1LL)%m,p[s]=(m*1U+*p-a)*(h?1LL:c)%m,*p=(a*1U+*p)%m,p++,c=c*1LL*d%m;}l(){while(e/=2){N*=2;U=U*1LL*(m+1)/2%m;for(s=N;s/=2;)g(136,0);for(p=t;p<t+N;p++)*p=*p*1LL**p%m*U%m;for(s=1;s<N;s*=2)g(839354248,1);for(a=0,p=t;p<t+N;)a+=*p<<(e&1),*p++=a,a/=10;}}z(n){int y=3,j,c;for(j=2;j<=n;){l();for(c=2;c<=y-1;c++){l();if(y%c==0)break;}if(c==y){l();j++;}y++;}l();return y-1;}main(a, pq) char* pq;{int b=sizeof(S),y=b,j=M;l();int x[M]={b-M-sizeof((short int) a),(b>>v)+(k<<v)+ (v<<(q|ef)) + z(v+(ef<<v)),(z(k*ef)<<v)-pow(ef,f), z(( (j-ef*k)|(ef<<k>>v)/k-ef<<v)-ef),(((y+M)&b)<<(k/q+ef))-z(ef+v),((ef<<k)-v)&y,y*v+v,(ef<<(q*ef-v-(k>>ef)))*q-v,(f<<q)|(ef<<(q*f+k))-j+k,(z(z(z(z(z(v)))))*q)&(((j/q)-(ef<<v))<<q)|(j+(q|(ef<<v))),y|(q+v),(ef<<ef)-v+ef*(((j>>ef)|j)-v+ef-q+v),(z(j&(b<<ef))&(z(v<<v)<<k))-(q<<v)-q,(k<<q)+q,(z(y)>>(ef<<v))+(z(k+v))-q,(z(z(k&ef|j))&b|ef|v<<f<<q<<v&ef>>k|q<<ef<<v|k|q)+z(v<<v)+v,(ef>>v)*q*z(k-v)+z(ef<<ef&q|k)+ef,z(k<<k)&v&k|y+k-v,z(f>>ef|k>>ef|v|k)*(ef>>v)*q,(ef<<k-ef<<v>>q<<ef*ef)-j+(ef<<v),z(ef*k)*z(v<<v)+k-v,z((z(k)<<z(v)))&y|k|v,z(ef<<ef<<v<<v)/ef+z(v<<ef|k|(b>>q)&y-f)-(ef<<q)+(k-v)-ef,k<<(ef+q)/z(ef)*z(q)&z(k<<k)|v,((z(y|j>>k*ef))�<<z(v<<v<<v)>>q<<q|j)/ef+v,(j-ef<<ef<<v*z(v>>v<<v)>>ef)/ef%z(k<<j)+q,z(k-v)+k|z(ef<<k>>v<<f)-z(q<<q)*ef>>v,(z(ef|y&j|k)%q|j+ef<<z(k|ef)%k<<q|ef|k<<ef<<q/ef|y/ef+j>>q)&k<<j|ef+v,84,z(v*ef<<ef<<q)*q�<<k|k|q-v,((z(20)*v)|(f>>q)|(k<<k))/ef-(ef<<(v*q+ef))-(k<<q)+z(k)-q};while(j--){putchar(x[M-v-j]);}printf(" From ASIS With Love <3\n");return 0;}
- そのままコンパイルするとめっちゃ怒られた.
hamasho30@hamasho30-virtual-machine:~$ gcc warmup.c warmup.c:7:8: error: unknown type name ‘int64_t’ struct b{int64_t y[13];}S;int m=1811939329,N=1,t[1<<26]={2},a,*p,i,e=73421233,s,c,U=1;g(d,h){for(i=s;i<1<<25;i*=2)d=d*1LL*d%m;for(p=t;p<t+N;p+=s)for(i=s,c=1;i;i--)a=p[s]*(h?c:1LL)%m,p[s]=(m*1U+*p-a)*(h?1LL:c)%m,*p=(a*1U+*p)%m,p++,c=c*1LL*d%m;}l(){while(e/=2){N*=2;U=U*1LL*(m+1)/2%m;for(s=N;s/=2;)g(136,0);for(p=t;p<t+N;p++)*p=*p*1LL**p%m*U%m;for(s=1;s<N;s*=2)g(839354248,1);for(a=0,p=t;p<t+N;)a+=*p<<(e&1),*p++=a,a/=10;}}z(n){int y=3,j,c;for(j=2;j<=n;){l();for(c=2;c<=y-1;c++){l();if(y%c==0)break;}if(c==y){l();j++;}y++;}l();return y-1;}main(a, pq) char* pq;{int b=sizeof(S),y=b,j=M;l();int x[M]={b-M-sizeof((short int) a),(b>>v)+(k<<v)+ (v<<(q|ef)) + z(v+(ef<<v)),(z(k*ef)<<v)-pow(ef,f), z(( (j-ef*k)|(ef<<k>>v)/k-ef<<v)-ef),(((y+M)&b)<<(k/q+ef))-z(ef+v),((ef<<k)-v)&y,y*v+v,(ef<<(q*ef-v-(k>>ef)))*q-v,(f<<q)|(ef<<(q*f+k))-j+k,(z(z(z(z(z(v)))))*q)&(((j/q)-(ef<<v))<<q)|(j+(q|(ef<<v))),y|(q+v),(ef<<ef)-v+ef*(((j>>ef)|j)-v+ef-q+v),(z(j&(b<<ef))&(z(v<<v)<<k))-(q<<v)-q,(k<<q)+q,(z(y)>>(ef<<v))+(z(k+v))-q,(z(z(k&ef|j))&b|ef|v<<f<<q<<v&ef>>k|q<<ef<<v|k|q)+z(v<<v)+v,(ef>>v)*q*z(k-v)+z(ef<<ef&q|k)+ef,z(k<<k)&v&k|y+k-v,z(f>>ef|k>>ef|v|k)*(ef>>v)*q,(ef<<k-ef<<v>>q<<ef*ef)-j+(ef<<v),z(ef*k)*z(v<<v)+k-v,z((z(k)<<z(v)))&y|k|v,z(ef<<ef<<v<<v)/ef+z(v<<ef|k|(b>>q)&y-f)-(ef<<q)+(k-v)-ef,k<<(ef+q)/z(ef)*z(q)&z(k<<k)|v,((z(y|j>>k*ef))�<<z(v<<v<<v)>>q<<q|j)/ef+v,(j-ef<<ef<<v*z(v>>v<<v)>>ef)/ef%z(k<<j)+q,z(k-v)+k|z(ef<<k>>v<<f)-z(q<<q)*ef>>v,(z(ef|y&j|k)%q|j+ef<<z(k|ef)%k<<q|ef|k<<ef<<q/ef|y/ef+j>>q)&k<<j|ef+v,84,z(v*ef<<ef<<q)*q�<<k|k|q-v,((z(20)*v)|(f>>q)|(k<<k))/ef-(ef<<(v*q+ef))-(k<<q)+z(k)-q};while(j--){putchar(x[M-v-j]);}printf(" From ASIS With Love <3\n");return 0;} ^ (省略)
- 上のエラーメッセージで、int64_t が定義されていないと言われている.
- この辺を参考に、1行追加する.
- http://www.wdic.org/w/TECH/int64_t
#define M 37 #define q (2+M/M) #define v (q/q) #define ef ((v+q)/2) #define f (q-v-ef) #define k (8-ef) typedef long int int64_t; struct b{int64_t y[13];}S;int m=1811939329,N=1,t[1<<26]={2},a,*p,i,e=73421233,s,c,U=1;g(d,h){for(i=s;i<1<<25;i*=2)d=d*1LL*d%m;for(p=t;p<t+N;p+=s)for(i=s,c=1;i;i--)a=p[s]*(h?c:1LL)%m,p[s]=(m*1U+*p-a)*(h?1LL:c)%m,*p=(a*1U+*p)%m,p++,c=c*1LL*d%m;}l(){while(e/=2){N*=2;U=U*1LL*(m+1)/2%m;for(s=N;s/=2;)g(136,0);for(p=t;p<t+N;p++)*p=*p*1LL**p%m*U%m;for(s=1;s<N;s*=2)g(839354248,1);for(a=0,p=t;p<t+N;)a+=*p<<(e&1),*p++=a,a/=10;}}z(n){int y=3,j,c;for(j=2;j<=n;){l();for(c=2;c<=y-1;c++){l();if(y%c==0)break;}if(c==y){l();j++;}y++;}l();return y-1;}main(a, pq) char* pq;{int b=sizeof(S),y=b,j=M;l();int x[M]={b-M-sizeof((short int) a),(b>>v)+(k<<v)+ (v<<(q|ef)) + z(v+(ef<<v)),(z(k*ef)<<v)-pow(ef,f), z(( (j-ef*k)|(ef<<k>>v)/k-ef<<v)-ef),(((y+M)&b)<<(k/q+ef))-z(ef+v),((ef<<k)-v)&y,y*v+v,(ef<<(q*ef-v-(k>>ef)))*q-v,(f<<q)|(ef<<(q*f+k))-j+k,(z(z(z(z(z(v)))))*q)&(((j/q)-(ef<<v))<<q)|(j+(q|(ef<<v))),y|(q+v),(ef<<ef)-v+ef*(((j>>ef)|j)-v+ef-q+v),(z(j&(b<<ef))&(z(v<<v)<<k))-(q<<v)-q,(k<<q)+q,(z(y)>>(ef<<v))+(z(k+v))-q,(z(z(k&ef|j))&b|ef|v<<f<<q<<v&ef>>k|q<<ef<<v|k|q)+z(v<<v)+v,(ef>>v)*q*z(k-v)+z(ef<<ef&q|k)+ef,z(k<<k)&v&k|y+k-v,z(f>>ef|k>>ef|v|k)*(ef>>v)*q,(ef<<k-ef<<v>>q<<ef*ef)-j+(ef<<v),z(ef*k)*z(v<<v)+k-v,z((z(k)<<z(v)))&y|k|v,z(ef<<ef<<v<<v)/ef+z(v<<ef|k|(b>>q)&y-f)-(ef<<q)+(k-v)-ef,k<<(ef+q)/z(ef)*z(q)&z(k<<k)|v,((z(y|j>>k*ef))�<<z(v<<v<<v)>>q<<q|j)/ef+v,(j-ef<<ef<<v*z(v>>v<<v)>>ef)/ef%z(k<<j)+q,z(k-v)+k|z(ef<<k>>v<<f)-z(q<<q)*ef>>v,(z(ef|y&j|k)%q|j+ef<<z(k|ef)%k<<q|ef|k<<ef<<q/ef|y/ef+j>>q)&k<<j|ef+v,84,z(v*ef<<ef<<q)*q�<<k|k|q-v,((z(20)*v)|(f>>q)|(k<<k))/ef-(ef<<(v*q+ef))-(k<<q)+z(k)-q};while(j--){putchar(x[M-v-j]);}printf(" From ASIS With Love <3\n");return 0;}
- 今度はコンパイルが通る.(warningは残るが無視する)
- 生成されたファイルを実行して暫く待つとFlagが表示される.
hamasho@hamasho-virtual-machine:~$ ./a.out ASIS{hi_all_w31c0m3_to_ASISCTF} From ASIS With Love <3
Flag : ASIS{hi_all_w31c0m3_to_ASISCTF}
Plastic(Misc, 64pt)
画像ファイルが与えられる.
- Flagの一部が見えている.
画像ファイルの中にBase64っぽい部分があるのでデコードする.
<rdf:li xml:lang="x-default">AAAFWHjabVRfbBRFGJ/ZOeifa+m2hVJaoNf2iohQtndX9ipS29IeVuwVe/1zbfc4
5/bm7pbu7V5255DjaDISozExaggxSIxC+2KRqBhjCPFBQwgmPggtSnySFx98IP57
ML4590dEw2w2+33fzHzz+37fbyeW0TWbStIdKCDHuvUvngi7jxPL1kwj7DZjx4hK
7Vk3ttSUxsOTbmpmGgB85cLHYntFZXtHp7trx2M7H9/1RI+/78DgoWeC4zNhJarG
U7pp0ym3kdX1tapqZ02TayYY6l4gOXuOf8t5p92qjm17pXZDnVjf0LhxExMYYg62
jq1nFaySVbHqlc3NW1pat27b3sacrIZtYHWsnrWwVraNbWeucAzbRNcMMqWaumlN
ps04maIa1Uk4YxGcjukkksZJQ0toKqa8pMk4piQq1sWwupC0zKwRP1jYOGebWUsl
k+QE7QTlsbZ7j7N7rzQVDE0cGlKCoeLCUAarZFzcJXX3+fd5fL19/j6/S+qWJLnH
I/XxIXsLrkf2eX0Sj/YCEbLaVY/X1ztXKtbAaRIumcSeKadd2if/Y4aDofEiO6Jj
1fnk/qdmOV02tTQjycQjPFH/0xx+MDSWpZhXFyrOLPcPyHxfyVkbch4cHgk88Dn0
QcqtWJYSmzWwLawxKq4qcVPNpolBi0jme6QMjeSxRTVVJ4vVStYmvNIFnCTz3Cxg
tiP5IseLri4eibsSpsVfg7qK0Yd35HHatnPpGF+ZxjRl/3+uEHzU3HyWJvyRvGZk
OFJDLR2UyOouarpoLkNccc3ivOg5bmDV0jhWl5rCFlYp12t1QWajh8cuPss2XnyO
bWLN08FQgAO8c+T5CWdocmqa+yHtJOHEJAI6TtrcD/LCOgd2lhouiqyJbZ4eMw2s
mpzp2blyhqV5uWzxaOQoJ3RYUwtqwlZuKSLz4As4KjY8xHO8RP1STH5kvHNgqHTk
KnEmkoUfg2ocyOCXfrLwp/oT28pTasf4mcNcrUsLctkqKDK9Vwr0uPgDWG2h05mR
AGsr9fRAXoklXIOh0dCiku+V0l4l6stkbCWa7R1RomNeGXPx+5RofNyQlehonyFN
ECVKU96x9nZlkR+ZPR4VGx9I698al7MRuSi6wyRH4oPlq+B27uSkZZqUQVAJ6kEL
6AR7gAfIYB5gkAIZkAenwevgDfAWOAPOgrfBOXAevAveAx+AS+Ay+Ah8Aj4Fn4HP
wVVwDXwBboBvwC3wPfgR3Ae/Qwesg82wDXZBD4xCDFWYgjY8BV+Gr8I34Tl4Hr4P
V+CH8DK8Aq/Dm/AWvAvvwfvwF/gb/EP4WvhWuC2sCd8Jd4UfhHvCz8Kvwl8IoCrk
RLWoDjWhVtSButBu1IP60SAKoHl0FNnoFHoJvYbOoLPoHXQBLaNL6Aq6iq6hr9B1
dAPddFQ4ahwdjh0Ov2O/Y6DUQQGWr4s8+M9wDP0NfUGwlA==
</rdf:li>
- デコードすると変なバイナリデータが得られた.
- とりあえずbinwalkに喰わせてみる.
hamasho@hamasho-virtual-machine:~$ binwalk 1.bin DECIMAL HEX DESCRIPTION -------------------------------------------------------------------------------------------------------
- 本当に???と思って-aオプションを付ける.
- zlibデータが埋まっているらしい.
hamasho@hamasho-virtual-machine:~$ binwalk -a 1.bin DECIMAL HEX DESCRIPTION ------------------------------------------------------------------------------------------------------- 4 0x4 zlib compressed data
binwalkでzlibデータを--ddオプション等で切り出そうと思ったが抽出してくれなかった. 手動で切り出す.
- binwalkってzlibは取り出してくれないんでしたっけ?
zlibで圧縮されているデータはPythonでデコードする.
- 適当にググったら過去のCTFのWriteupでワンライナーを書いている方がいたので流用させていただきました.
stringsコマンドに掛けると「ASIS」の文字が見えた.
hamasho@hamasho-virtual-machine:~$ python -c 'import zlib; print zlib.decompress(open("1.bin").read())' | strings bplist00 wxX$versionX$objectsY$archiverT$top !"#$%&'()*+189=AGHNOWX\_cdhlostU$null WNS.keysZNS.objectsV$class XbaselineUcolorTmodeUtitleXpreamble]magnificationTdate_ backgroundColorZsourceText# ./0UNSRGB\NSColorSpaceO *0.9862459898 0.007120999973 0.02743400075 2345Z$classnameX$classesWNSColor 67WNSColorXNSObject :;<YNS.string 23>?_ NSMutableString >@7XNSString CDEFXNSString\NSAttributes \documentclass[10pt]{article} \usepackage[usenames]{color} %used for font color \usepackage{amssymb} %maths \usepackage{amsmath} %maths \usepackage[utf8]{inputenc} %useful to type directly diacritic characters VNSFont STUVVNSSizeXNSfFlagsVNSName#@( VMonaco 23YZVNSFont [7VNSFont 23]^\NSDictionary 23`a_ NSAttributedString NSAttributedString#@B fgWNS.time#A 23ijVNSDate k7VNSDate m/0F1 1 1 CpEF ={\bf ASIS}\{50m3\_4pps\_u5E\_M37adat4\_dOn7\_I9n0Re\_th3M!!\} 23uv_ NSMutableDictionary u]7_ NSKeyedArchiver yzTroot
- 「Some Apps Use Metadata don't Ignore them」 か?
Flag : ASIS{50m3_4pps_u5E_M37adat4_dOn7_I9n0Re_th3M!!}
baby C(Reverse, 83pt)
- 激しく難読化されている感じがするELFファイルが与えられる.
ハードコードされている文字列 "m0vfu3c4t0r!" を "movfuscator"に置き換えてGoogle検索.
- 何かそれっぽいものが見つかった.
- https://github.com/xoreaxeaxeax/movfuscator
- Control flow graphsが一直線になっているあたりが似ている感じがする.
調べると対応する難読化解除ツールっぽいものが見つかった.
難読化を解除したバイナリを読んでいく.
- x86のELFファイル.
hamasho@hamasho-virtual-machine:‾$ file babyc2 babyc2: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), stripped
- 適当な文字を入力すると「Wrong!」と表示されて落ちる.
hamasho@hamasho-virtual-machine:‾$ ./babyc2 A Wrong! Segmentation fault (コアダンプ)
IDA Proでバイナリを眺めていく.
最初に read() で標準入力からの入力を受け付ける.
ハードコードされている文字列を dword_804D050 にコピーする処理が複数回行われる.
- "0y1ng:(" がEAXの指すアドレスに保存されている.
.text:08048ECB mov edx, dword_81F6110 .text:08048ED1 mov [eax], edx .text:08048ED3 mov dword_804D050, '0' .text:08048F00 mov dl, byte ptr dword_804D050 .text:08048F06 mov [eax], dl .text:08048F08 mov dword_804D050, 'y' .text:08048FBC mov dl, byte ptr dword_804D050 .text:08048FC2 mov [eax], dl .text:08048FC4 mov dword_804D050, '1' .text:08049078 mov dl, byte ptr dword_804D050 .text:0804907E mov [eax], dl .text:08049080 mov dword_804D050, 'n .text:08049134 mov dl, byte ptr dword_804D050 .text:0804913A mov [eax], dl .text:0804913C mov dword_804D050, 'g' .text:08049163 mov dl, byte ptr dword_804D050 .text:08049169 mov [eax], dl .text:0804916B mov dword_804D050, ':' .text:0804921F mov dl, byte ptr dword_804D050 .text:08049225 mov [eax], dl .text:08049227 mov dword_804D050, '(' .text:080492DB mov dl, byte ptr dword_804D050 .text:080492E1 mov [eax], dl .text:080492E3 mov dword_804D05C, 0Ch
- "m0vfu3c4t0r!"という文字列も使用するっぽい.
.text:0804933D mov eax, offset aM0vfu3c4t0r ; "m0vfu3c4t0r!" .text:08049342 mov dword_804D05C, eax .text:08049347 mov eax, dword_804D05C
- 上の処理の後で、strncmp() を実行する.
.text:0804956C mov dword_85F61C4, offset loc_8048280 ... .plt:08048280 jmp ds:strncmp_ptr ...
- strncmp()で比較している文字列を確認すると, 入力値の先頭から4文字目の値から順にチェックしているっぽい.
比較対象は上のハードコードされていた文字列.
- 6D, 30, 76 と続いているので、入力値[3:]からの値が m0vfu3c4t0r! かどうかをチェックしている.
- 入力を期待される文字列は "???m0vfu3c4t0r!" のような形.
dword_804D05C に注目しつつ更に見ていくと, 似たような処理の塊が3つ続いている.
- このハードコードされた3文字 "Ah_" が "m0vfu3c4t0r!" の前に来るはずの3文字と推測できる.
.text:080498C8 mov dl, byte ptr dword_804D050 .text:080498CE mov edx, dword_81F5B70[edx*4] .text:080498D5 mov dword_804D05C, edx .text:080498DB mov dword_804D058, 'A' ... .text:08049B1F test eax, eax .text:08049B21 nop .text:08049B22 nop .text:08049B23 nop .text:08049B24 nop .text:08049B25 nop .text:08049B26 jnz loc_804B3F6 ... ... .text:08049BF2 mov dl, byte ptr dword_804D050 .text:08049BF8 mov edx, dword_81F5B70[edx*4] .text:08049BFF mov dword_804D05C, edx .text:08049C05 mov dword_804D058, 'h' ... .text:08049E49 test eax, eax .text:08049E4B nop .text:08049E4C nop .text:08049E4D nop .text:08049E4E nop .text:08049E4F nop .text:08049E50 jnz loc_804B3F6 ... ... .text:08049F1C mov dl, byte ptr dword_804D050 .text:08049F22 mov edx, dword_81F5B70[edx*4] .text:08049F29 mov dword_804D05C, edx .text:08049F2F mov dword_804D058, '_' ... .text:0804A173 test eax, eax .text:0804A175 nop .text:0804A176 nop .text:0804A177 nop .text:0804A178 nop .text:0804A179 nop .text:0804A17A jnz loc_804B3F6
更に進めていくと、再び strncmp() で文字列の比較が行われる.
- 今度は最初の方に確認した "0y1ng:(" がチェックされている.
- "Ah_m0vfu3c4t0r!0y1ng:(" で通りそうだなと思って入力したら違った.
もう少し見ていくと、他にもハードコードされている文字列があった.
- "y0"の部分を上書きしているか?
.text:0804A7BD mov dword_804D058, 'y0nn'
入力値は "Ah_m0vfu3c4t0r!nn0y1ng:(" で良さそう!と思って意気揚々と入力したがまたしてもwrong!になった.
- 細かく確認せずに飛ばしていた, 2回目の strncmp() の比較処理を確認する.
- 内部では, 入力値の一部である "1ng:(" と "0y1ng:(" が比較されている.(2文字分のズレがある)
- ハードコードされた "nn0y" の前に2文字追加してあげると比較処理を抜けられそう.
- 適当にAAを詰めて "Ah_m0vfu3c4t0r!AAnn0y1ng:(" と入力してみたところ、比較処理を抜けた.
そのままデバッグしていくと puts() を実行してCorrect :) と出力された.
- 適当に入れた2文字についてはどうやらチェックしていないようで, 値はなんでも良さそう.
- 問題文をちゃんと読んでおらず忘れていたが, 「flag is ASIS{sha1(input[:14])}」 と書いてあるので, 必要な文字列は「Ah_m0vfu3c4t0r」まで.
- だから "!" 直後の2文字は何でも良い形になっているのか?
hamasho@hamasho-virtual-machine:‾$ ./babyc2 Ah_m0vfu3c4t0r!AAnn0y1ng:( Correct :) Segmentation fault (コアダンプ) hamasho@hamasho-virtual-machine:‾$ echo -n "Ah_m0vfu3c4t0r" | openssl sha1 (stdin)= 574a1ebc69c34903a4631820f292d11fcd41b906
Flag : ASIS{574a1ebc69c34903a4631820f292d11fcd41b906}
Trashy Or Classy(Forensics, 118pt)
解けなかった問題.
pcapファイルが与えられる.
IPアドレス 167 . 99 . 233 . 88 に対して大量の通信が発生している.
- 通信の殆どがHTTPリクエストで、404 Not Foundが返っている.
- 適当なパスだったり, 特定のアプリケーションが使用するファイルパスだったりに通信しようとしている.
404 以外が返っているリクエストは無いのかな~と思って探してみると, 401 Unauthorized が返っているのがあった.
- 401が返ったあとで, Authorizationヘッダにデータを追加して再アクセスを行い, 200 OKが返っている.
- これはDigest認証っぽい. 仕組みはWikipediaとかをご参照ください.
- https://ja.wikipedia.org/wiki/Digest認証
5943番のTCPストリーム
GET /private/ HTTP/1.1 Host: 167.99.233.88 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Firefox/52.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate DNT: 1 Connection: keep-alive Upgrade-Insecure-Requests: 1 HTTP/1.1 401 Unauthorized Date: Fri, 27 Apr 2018 21:32:35 GMT Server: Apache WWW-Authenticate: Digest realm="Private Area", nonce="dUASPttqBQA=7f98746b6b66730448ee30eb2cd54d36d5b9ec0c", algorithm=MD5, domain="/", qop="auth" Content-Length: 381 Content-Type: text/html; charset=iso-8859-1 Connection: close <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"> <html><head> <title>401 Unauthorized</title> </head><body> <h1>Unauthorized</h1> <p>This server could not verify that you are authorized to access the document requested. Either you supplied the wrong credentials (e.g., bad password), or your browser doesn't understand how to supply the credentials required.</p> </body></html>
- 5944番のTCPストリーム
GET /private/ HTTP/1.1 Host: 167.99.233.88 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Firefox/52.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate DNT: 1 Connection: keep-alive Upgrade-Insecure-Requests: 1 Authorization: Digest username="admin", realm="Private Area", nonce="dUASPttqBQA=7f98746b6b66730448ee30eb2cd54d36d5b9ec0c", uri="/private/", algorithm=MD5, response="3823c96259b479bfa6737761e0f5f1ee", qop=auth, nc=00000001, cnonce="edba216c81ec879e" HTTP/1.1 200 OK Date: Fri, 27 Apr 2018 21:32:38 GMT Server: Apache Authentication-Info: rspauth="05d0b41966929e0102e595da3d4e8ab4", cnonce="edba216c81ec879e", nc=00000001, qop=auth Vary: Accept-Encoding Content-Encoding: gzip Content-Length: 432 Content-Type: text/html;charset=UTF-8 Connection: keep-alive ............_o. ....).x.[r.t...3.v.EK...TMS...6*.........xS.nZ....r.1..I....b....SX|=.Nb =....1Y&..a......q<#...~....Br.F.^y-...y.6.,...^Rl6..-KWV<.%....uS..6...c..p...MD.- .j.C....J..p.....*#.....I<.....>.(...,"..hv2...f|.........6.....*SR../..R=./.4L"....+k.(..]...U.....A..T......oa,N/..e2.h".u..:$l..4...d..{h.5.[.....Khov*/<a.=.I.......;.U....5.<..\.{.....?.......]op.....1.>#../.k$.ZH.../.V{...2R/^...../....Hq...17...nt^>1...
- 更に見ていくと, /private/ の下に flag.castr と flag.caidx が存在することが分かった.
GET /private/flag.castr/ HTTP/1.1 Host: 167.99.233.88 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Firefox/52.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate Referer: http://167.99.233.88/private/ DNT: 1 Authorization: Digest username="admin", realm="Private Area", nonce="dUASPttqBQA=7f98746b6b66730448ee30eb2cd54d36d5b9ec0c", uri="/private/flag.castr/", algorithm=MD5, response="4eb62a087ed8f9a95c8eb4172a23d085", qop=auth, nc=00000002, cnonce="6a93259e6d1b94e9" Connection: keep-alive Upgrade-Insecure-Requests: 1 HTTP/1.1 403 Forbidden Date: Fri, 27 Apr 2018 21:32:40 GMT Server: Apache Content-Length: 228 Content-Type: text/html; charset=iso-8859-1 Connection: close <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"> <html><head> <title>403 Forbidden</title> </head><body> <h1>Forbidden</h1> <p>You don't have permission to access /private/flag.castr/ on this server.<br /> </p> </body></html>
GET /private/flag.caidx HTTP/1.1 Host: 167.99.233.88 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Firefox/52.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate Referer: http://167.99.233.88/private/ DNT: 1 Authorization: Digest username="admin", realm="Private Area", nonce="dUASPttqBQA=7f98746b6b66730448ee30eb2cd54d36d5b9ec0c", uri="/private/flag.caidx", algorithm=MD5, response="a4db2608bc1c9cb99cea65438cfb61ac", qop=auth, nc=00000003, cnonce="3a46ba35c226ab51" Connection: keep-alive Upgrade-Insecure-Requests: 1 HTTP/1.1 200 OK Date: Fri, 27 Apr 2018 21:32:45 GMT Server: Apache Authentication-Info: rspauth="9feb03ba70ce0cc785e46b07fbe1c49b", cnonce="3a46ba35c226ab51", nc=00000003, qop=auth Last-Modified: Sun, 08 Apr 2018 10:29:57 GMT Accept-Ranges: bytes Content-Length: 29384 Connection: keep-alive
この /private/ にアクセスする必要がありそうな気がする.
- ただし, flag.castr へのアクセスは adminユーザでも失敗しているので, ログインするだけでは駄目かもしれない.
- 同じディレクトリに他のファイル(ヒント)があったりするのか?
Digest認証は様々なデータをAuthorizationヘッダで送信する.
- 今回は、パケットからusername、realm、http_method、uri、qop、nc、cnonce、nonce、responceが分かる.
- 分からないのはpasswordぐらい.
- 他の要素からpasswordを推測出来ないか考えてみる.
Digest認証で送信するデータの形は以下のようになる.
a1 = username:realm:password a2 = http_method:uri response = md5(md5(a1):nonce:nc:cnonce:qop:md5(a2))
単純な総当たりは時間がかかりそうだったので、適当なパスワードリストを拾ってきて, それを使ってブルートフォースした.
- password = "rainbow" の時に responce の値が一致した.
admin:rainbowで http://167.99.233.88/private/ にアクセスしてみるとログインできた.
この拡張子でググると、casyncというツールがヒットした.
- https://github.com/systemd/casync
- また, .caidxファイルはディレクトリツリーの情報を持つインデックスファイルの一種であることがわかった.
- このツールを使うと.caidxファイルの調査が行えそうだったが, ツールのインストールが上手くいかず止まってしまった.
- 他の方のwriteupを見る感じだと、casyncで調査して行く感じであっていたっぽいので悔しい
おわりに
ツールのを動かすための環境構築でハマって時間が溶けるのが辛い。手を付けられていないpwnとreverseの問題を復習したい。