Security Tech Lounge Vol.6 春のCTFセンバツ 供養(Writeup)
Security Tech Lounge Vol.6 春のCTFセンバツに参加。12チーム中1位。
packet (100)
pcapngファイルが与えられる。
$ file packet packet: pcap-ng capture file - version 1.0
Wiresharkで開くとICMPパケットが並んでおり、パケット長が3種類の異なるバイト数になっていることがわかる。
ICMPリクエストのパケット長を取り出し、.01
に置き換えてみる。
$ tshark -r packet.pcap -T fields -e frame.len 'icmp.type==8' >packet.txt $ head packet.txt 98 98 98 98 98 98 98 98 98 98 $ cat solve.py s = '' with open('packet.txt') as f: for line in f: if line.startswith('98'): s += '.' elif line.startswith('99'): s += '0' elif line.startswith('153'): s += '1' print(s) $ python3 solve.py ..........1000110.1001100.1000001.1000111.1011111.1110000.1101001.1101110.1100111.0110010.1100011...............................
2進数で表現されたASCII文字として解釈すると、フラグが得られた。
$ python3 Python 3.6.7 (default, Oct 22 2018, 11:32:17) [GCC 8.2.0] on linux Type "help", "copyright", "credits" or "license" for more information. >>> ary = '1000110.1001100.1000001.1000111.1011111.1110000.1101001.1101110.1100111.0110010.1100011'.split('.') >>> ''.join(chr(int(x,2)) for x in ary) 'FLAG_ping2c'
bin (125)
64 bit ELF実行ファイルが与えられる。
$ file ctf ctf: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/l, for GNU/Linux 3.2.0, stripped
実行すると、localhostのUDP 53(DNS)にsendto(2)でデータを繰り返し送信していることがわかる。
$ chmod +x ctf $ strace ./ctf (snip) sendto(11, "p\2\1\0\0\1\0\0\0\0\0\1'RFIE4RYNBINAUAAAAAG"..., 78, 0, NULL, 0) = 78 recvfrom(11, 0x42001d7010, 16384, 0, NULL, NULL) = -1 ECONNREFUSED (Connection refused) write(9, "\1\0\0\0\0\0\0\0", 8) = 8 close(11) = 0 futex(0x7fca08000bac, FUTEX_WAKE_PRIVATE, 1) = 1 futex(0x7fca08000bb0, FUTEX_WAKE_PRIVATE, 1) = 1 futex(0x7daa88, FUTEX_WAKE_PRIVATE, 1) = 1 socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP) = 11 fcntl(11, F_GETFL) = 0x2 (flags O_RDWR) fcntl(11, F_SETFL, O_RDWR|O_NONBLOCK) = 0 connect(11, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("127.0.0.1")}, 16) = 0 write(9, "\1\0\0\0\0\0\0\0", 8) = 8 sendto(11, "\2244\1\0\0\1\0\0\0\0\0\1%IAYAAAAEE7P7MEAAAAA"..., 76, 0, NULL, 0) = 76 recvfrom(11, 0x42001ce010, 16384, 0, NULL, NULL) = -1 ECONNREFUSED (Connection refused) write(9, "\1\0\0\0\0\0\0\0", 8) = 8 close(11) = 0 futex(0x7fca08000ba8, FUTEX_WAKE_PRIVATE, 1) = 1 futex(0x7fca08000bb0, FUTEX_WAKE_PRIVATE, 1) = 1 futex(0x7daa88, FUTEX_WAKE_PRIVATE, 1) = 1 socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP) = 11 fcntl(11, F_GETFL) = 0x2 (flags O_RDWR) fcntl(11, F_SETFL, O_RDWR|O_NONBLOCK) = 0 connect(11, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("127.0.0.1")}, 16) = 0 write(9, "\1\0\0\0\0\0\0\0", 8) = 8 sendto(11, "\235b\1\0\0\1\0\0\0\0\0\1'JCAAAAAAS4CILFZQAAA"..., 78, 0, NULL, 0) = 78 recvfrom(11, 0x42001c5010, 16384, 0, NULL, NULL) = -1 ECONNREFUSED (Connection refused) write(9, "\1\0\0\0\0\0\0\0", 8) = 8 close(11) = 0 (snip)
sendto(2)に絞ってデータを詳しく見ると、*.localhost
に対する名前解決を繰り返しているように見える。
そこで、.localhost
を除いたドメイン名のみを取り出してみる。
$ strace -e trace=sendto -s1000 ./ctf Sending data... sendto(11, {{len=20, type=RTM_GETADDR, flags=NLM_F_REQUEST|NLM_F_DUMP, seq=1554171854, pid=0}, {ifa_family=AF_UNSPEC, ...}}, 20, 0, {sa_family=AF_NETLINK, nl_pid=0, nl_groups=00000000}, 12) = 20 sendto(11, "\251\277\1\0\0\1\0\0\0\0\0\1'RFIE4RYNBINAUAAAAAGUSSCEKIAAAAM7AAAACOA\tlocalhost\0\0\20\0\1\0\0)\20\0\0\0\0\0\0\0", 78, 0, NULL, 0) = 78 sendto(11, "\5@\1\0\0\1\0\0\0\0\0\1%IAYAAAAEE7P7MEAAAAACHGQSJKQEAQCAIPQEG\tlocalhost\0\0\20\0\1\0\0)\20\0\0\0\0\0\0\0", 76, 0, NULL, 0) = 76 sendto(11, "w,\1\0\0\1\0\0\0\0\0\1'JCAAAAAAS4CILFZQAAAPKQAAAD2UAFPLT46BAAA\tlocalhost\0\0\20\0\1\0\0)\20\0\0\0\0\0\0\0", 78, 0, NULL, 0) = 78 sendto(11, "\252\352\1\0\0\1\0\0\0\0\0\1%AAGLUIVMHIU3PMZ2HOYLSMUAHO53XFZUW423T\tlocalhost\0\0\20\0\1\0\0)\20\0\0\0\0\0\0\0", 76, 0, NULL, 0) = 76 (snip) $ strace -e trace=sendto -s1000 ./ctf |& grep -o -P '[\w=]+(?=\\tlocalhost)' | tee ctf.txt RFIE4RYNBINAUAAAAAGUSSCEKIAAAAM7AAAACOA IAYAAAAEE7P7MEAAAAACHGQSJKQEAQCAIPQEG JCAAAAAAS4CILFZQAAAPKQAAAD2UAFPLT46BAAA AAGLUIVMHIU3PMZ2HOYLSMUAHO53XFZUW423T (snip) BDXQAEAFQR7YAAAKYI34AAANMEJ6AAAOWCA7ACA HLBAPADADVQQHABQB3YIDACYI54ABABMEP6AA ACWCG7AAADLBCPQAADVQQHYAQB276D5FZLJGUEB 31MPHRQAAAAABEUKTSEVZBGBAQ=
コンテスト中はここまでしかわからず解けなかった。
取り出したデータをよく見ると、英大文字、数字、=
のみであることがわかる。
そこで、Base32 としてデコードしてみる。
最後の行のみBase32で使用されない 1
が含まれているため、最後の行を除きパディング文字 =
を調整した。
その結果データの先頭にPNGファイルのシグネチャが見えたため、これをPNGファイルとして保存する。
import base64 with open('ctf.txt') as f: lines = f.read().splitlines() data = ''.join(lines[:-1]) decoded = base64.b32decode(data + '=') print(decoded) with open('ctf.png', 'wb') as f: f.write(decoded)
$ python3 solve.py b'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x01\x9f\x00\x00\x018\x08\x06\x00\x00\x00\x84\xfb\xfe ...(snip)... \x8e\xf0\x01\x00XG\xf8\x00\x00\xac#|\x00\x00\xd6\x11>\x00\x00\xeb\x08\x1f\x00\x80u\xff\x0f\xa5\xca\xd2j\x10'
PNGファイルの末尾が欠けていることになるが、Firefoxブラウザで開くと画像が確認でき、フラグが得られた。
最後の行の 31
は \31
を誤って抜き出してしまった模様。
reg (150)
UTF-16LEのテキストファイルが与えられる。
$ file reg reg: Little-endian UTF-16 Unicode text, with very long lines, with CRLF, CR line terminators
内容を確認すると、Base64文字列が入ったレジストリ値二つとPowerShellスクリプトが入ったレジストリ値一つが書かれている。
$ cat reg ??Windows Registry Editor Version 5.00 [HKEY_LOCAL_MACHINE\SOFTWARE\Mandiant\CTF] "Anchovy"="QhdMGkZMUkxCRE9HT0xPXEIXTklMEVJD ...(snip)... EkMdRRJDHTdAThtMT05ETE9ORkxPRw==" "Herring"="bVNbi9s8EH2Of8UQDGuTKvShlI+Y72F3 ...(snip)... NnhBrNvRtg3rc+u32LMyPLcVQ/NeAA==" "Mackerel"="$raw=Get-ItemProperty('hklm:\\Software\\Mandiant\\CTF')|Select-Object -ExpandProperty Herring;sal a New-Object;iex(a IO.StreamReader((a IO.Compression.DeflateStream([IO.MemoryStream][Convert]::FromBase64String($raw),[IO.Compression.CompressionMode]::Decompress)),[Text.Encoding]::ASCII)).ReadToEnd()"
Mackerelのコードに従い、HerringのデータをBase64デコードしてDeflate展開すると次のようになる。
$ python3 Python 3.6.7 (default, Oct 22 2018, 11:32:17) [GCC 8.2.0] on linux Type "help", "copyright", "credits" or "license" for more information. >>> import base64 >>> import zlib >>> herring = 'bVNbi9s8EH2Of8UQDGuTKvShlI+Y72F3 ...(snip)... NnhBrNvRtg3rc+u32LMyPLcVQ/NeAA==' >>> zlib.decompress(base64.b64decode(herring), -15) b'function Invoke-AES {\n\t\tparam($e_str, $method)\n\t\t$enc = new-object -TypeName System.Text.UTF8Encoding\n\t\t$super_long_key = $enc.GetBytes("flog")\n\n\t\tif ($method -eq "decrypt"){\n\t\t\t$e_str = $enc.GetString([System.Convert]::FromBase64String($e_str))\n }\n\n\t\t$byteString = $enc.GetBytes($e_str)\n\t\t$AESdData = $(for ($i = 0; $i -lt $byteString.length; ) {\n\t\t\tfor ($j = 0; $j -lt $super_long_key.length; $j++) {\n\t\t\t\t$byteString[$i] -bxor $super_long_key[$j]\n\t\t\t\t$i++\n\t\t\t\tif ($i -ge $byteString.Length) {\n\t\t\t\t\t$j = $super_long_key.length\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\n\t\tif ($method -eq "encrypt") {\n\t\t\t$AESdData = [System.Convert]::ToBase64String($AESdData)\n\t\t} else {\n\t\t\t$AESdData = $enc.GetString($AESdData)\n\t\t}\n\n\t\treturn $AESdData\n}\n$RegPath = \'hklm:\\Software\\Mandiant\\CTF\';\n$raw = Get-ItemProperty $RegPath | Select-Object -ExpandProperty Anchovy;\n$raw_obj = Invoke-AES -e_str $raw -method decrypt;\niex $raw_obj;' >>> print(_.decode('utf-8')) function Invoke-AES { param($e_str, $method) $enc = new-object -TypeName System.Text.UTF8Encoding $super_long_key = $enc.GetBytes("flog") if ($method -eq "decrypt"){ $e_str = $enc.GetString([System.Convert]::FromBase64String($e_str)) } $byteString = $enc.GetBytes($e_str) $AESdData = $(for ($i = 0; $i -lt $byteString.length; ) { for ($j = 0; $j -lt $super_long_key.length; $j++) { $byteString[$i] -bxor $super_long_key[$j] $i++ if ($i -ge $byteString.Length) { $j = $super_long_key.length } } }) if ($method -eq "encrypt") { $AESdData = [System.Convert]::ToBase64String($AESdData) } else { $AESdData = $enc.GetString($AESdData) } return $AESdData } $RegPath = 'hklm:\Software\Mandiant\CTF'; $raw = Get-ItemProperty $RegPath | Select-Object -ExpandProperty Anchovy; $raw_obj = Invoke-AES -e_str $raw -method decrypt; iex $raw_obj;
PowerShellを使い、Anchovyのデータから作られる $raw_obj
の内容を調べてみる。
Windows PowerShell Copyright (C) 2009 Microsoft Corporation. All rights reserved. PS C:\Users\user> function Invoke-AES { >> param($e_str, $method) >> $enc = new-object -TypeName System.Text.UTF8Encoding >> $super_long_key = $enc.GetBytes("flog") >> >> if ($method -eq "decrypt"){ >> $e_str = $enc.GetString([System.Convert]::FromBase64String($e_str)) >> } >> >> $byteString = $enc.GetBytes($e_str) >> $AESdData = $(for ($i = 0; $i -lt $byteString.length; ) { >> for ($j = 0; $j -lt $super_long_key.length; $j++) { >> $byteString[$i] -bxor $super_long_key[$j] >> $i++ >> if ($i -ge $byteString.Length) { >> $j = $super_long_key.length >> } >> } >> }) >> >> if ($method -eq "encrypt") { >> $AESdData = [System.Convert]::ToBase64String($AESdData) >> } else { >> $AESdData = $enc.GetString($AESdData) >> } >> >> return $AESdData >> } >> PS C:\Users\user> $raw = "QhdMGkZMUkxCRE9HT0xPXEIXTklMEVJD ...(snip)... EkMdRRJDHTdAThtMT05ETE9ORkxPRw==" PS C:\Users\user> $raw_obj = Invoke-AES -e_str $raw -method decrypt; PS C:\Users\user> $raw_obj ${#} =+$( ) ;${!.*}=${#};${[/)}= ++ ${#} ;${).+}= ++${#} ; ${=-$} =++${#};${)}=++${#} ; ${+}= ++ ${#} ; ${``}= ++ ${#}; ${/} =++${#};${/[(}= ++ ${#};${+-.} = ++${#} ; ${;%$} = "[" +"$(@{} )"[ ${/}]+"$(@{})"[ "${[/)}"+"${+-.}"] + "$( @{ } )"[ "${).+}" +"${!.*}"] +"$? "[ ${[/)} ] + "]" ;${#}="".("$( @{} ) "[ "${[/)}" +"${)}"]+"$( @{} ) "["${[/)}" + "${``}" ]+ "$(@{ } ) "[${!.*}]+"$( @{}) "[ ${)} ] + "$?"[${[/)} ]+ "$(@{ } )"[ ${=-$}] ); ${#} ="$(@{ } )"["${[/)}" +"${)}" ] +"$(@{ })"[ ${)}] +"${#}"["${).+}"+"${/}" ] ;. ${#} ( " ${#}(${;%$}${``}${+}+ ${;%$}${[/)}${!.*}${!.*} + ${;%$}${[/)}${!.*}${!.*}+${;%$}${)}${+} +${;%$}${/[(}${)}+ ${;%$}${[/)}${).+}${[/)} + ${;%$}${[/)}${[/)}${).+}+${;%$}${[/)}${!.*}${[/)} + ${;%$}${=-$}${).+}+ ${;%$}${)}${+} +${;%$}${``}${+}+${;%$}${[/)}${[/)}${+} + ${;%$}${[/)}${[/)}${+} + ${;%$}${[/)}${!.*}${[/)} +${;%$}${[/)}${!.*}${+-.}+${;%$}${+-.}${/[(}+ ${;%$}${[/)}${!.*}${/[(} + ${;%$}${[/)}${).+}${[/)}+${;%$}${/}${/[(} + ${;%$}${+-.}${/}+ ${;%$}${[/)}${!.*}${+-.}+ ${;%$}${[/)}${!.*}${[/)}+${;%$}${=-$}${).+}+ ${;%$}${/[(}${=-$} + ${;%$}${[/)}${).+}${[/)} +${;%$}${[/)}${[/)}${+}+ ${;%$}${[/)}${[/)}${``} +${;%$}${[/)}${!.*}${[/)} + ${;%$}${[/)}${!.*}${+-.}+${;%$}${)}${``}+${;%$}${[/)}${[/)}${+}+${;%$}${[/)}${[/)}${).+} + ${;%$}${[/)}${!.*}${[/)} + ${;%$}${[/)}${!.*}${[/)}+${;%$}${+-.}${+-.} + ${;%$}${[/)}${!.*}${)}+ ${;%$}${[/)}${=-$}+ ${;%$}${[/)}${!.*}+ ${;%$}${=-$}${``}+${;%$}${[/)}${[/)}${+} + ${;%$}${[/)}${[/)}${).+}+ ${;%$}${[/)}${!.*}${[/)}+${;%$}${+-.}${/} +${;%$}${[/)}${!.*}${/}+${;%$}${=-$}${).+} + ${;%$}${``}${[/)} + ${;%$}${=-$}${).+}+${;%$}${/}${/[(} + ${;%$}${[/)}${!.*}${[/)}+${;%$}${[/)}${[/)}${+-.}+ ${;%$}${)}${+}+ ${;%$}${/}${+-.} + ${;%$}${+-.}${/[(} +${;%$}${[/)}${!.*}${``}+${;%$}${[/)}${!.*}${[/)} +${;%$}${+-.}${+-.} +${;%$}${[/)}${[/)}${``}+ ${;%$}${=-$}${).+}+ ${;%$}${/[(}${=-$}+${;%$}${[/)}${).+}${[/)}+${;%$}${[/)}${[/)}${+}+${;%$}${[/)}${[/)}${``}+ ${;%$}${[/)}${!.*}${[/)} + ${;%$}${[/)}${!.*}${+-.}+ ${;%$}${)}${``}+${;%$}${/[(}${=-$} +${;%$}${[/)}${[/)}${).+} + ${;%$}${[/)}${!.*}${[/)}+ ${;%$}${[/)}${!.*}${[/)} +${;%$}${+-.}${+-.}+${;%$}${[/)}${!.*}${)} +${;%$}${)}${``}+ ${;%$}${/[(}${=-$} +${;%$}${[/)}${).+}${[/)}+ ${;%$}${[/)}${[/)}${!.*} + ${;%$}${[/)}${[/)}${``}+ ${;%$}${[/)}${!.*}${)}+${;%$}${[/)}${!.*}${[/)} + ${;%$}${[/)}${[/)}${+} +${;%$}${[/)}${!.*}${+} +${;%$}${[/)}${[/)}${+}+ ${;%$}${)}${``} +${;%$}${/[(}${=-$}+ ${;%$}${[/)}${[/)}${).+} + ${;%$}${[/)}${!.*}${[/)} + ${;%$}${[/)}${!.*}${[/)} +${;%$}${+-.}${+-.} +${;%$}${[/)}${!.*}${)} +${;%$}${/[(}${=-$}+${;%$}${[/)}${).+}${[/)} + ${;%$}${[/)}${[/)}${!.*}+ ${;%$}${[/)}${[/)}${``}+ ${;%$}${[/)}${!.*}${)} + ${;%$}${[/)}${!.*}${[/)} + ${;%$}${[/)}${[/)}${+} + ${;%$}${[/)}${!.*}${+}+${;%$}${[/)}${).+}${).+}+${;%$}${[/)}${!.*}${[/)}+${;%$}${[/)}${[/)}${)} +${;%$}${[/)}${=-$}+ ${;%$}${[/)}${!.*}+${;%$}${=-$}${``} +${;%$}${[/)}${[/)}${+}+${;%$}${[/)}${[/)}${).+}+ ${;%$}${[/)}${!.*}${[/)}+${;%$}${+-.}${/} +${;%$}${[/)}${!.*}${/} +${;%$}${)}${``}+ ${;%$}${/[(}${=-$}+ ${;%$}${[/)}${[/)}${).+}+${;%$}${[/)}${!.*}${[/)}+ ${;%$}${+-.}${/}+ ${;%$}${[/)}${!.*}${/} + ${;%$}${)}${!.*}+${;%$}${=-$}${)}+ ${;%$}${/}${``}+ ${;%$}${[/)}${!.*}${+} + ${;%$}${[/)}${[/)}${+}+ ${;%$}${[/)}${[/)}${``} +${;%$}${[/)}${!.*}${[/)}+ ${;%$}${[/)}${[/)}${!.*} + ${;%$}${=-$}${=-$}+ ${;%$}${=-$}${).+}+${;%$}${/}${``} + ${;%$}${[/)}${!.*}${+} + ${;%$}${[/)}${[/)}${+} + ${;%$}${[/)}${[/)}${``}+${;%$}${[/)}${!.*}${[/)} + ${;%$}${[/)}${[/)}${!.*} +${;%$}${=-$}${=-$}+${;%$}${=-$}${).+} + ${;%$}${/}${!.*}+ ${;%$}${/}${``} +${;%$}${``}${+}+ ${;%$}${/}${[/)}+ ${;%$}${=-$}${).+} + ${;%$}${[/)}${!.*}${+}+ ${;%$}${[/)}${[/)}${+}+ ${;%$}${=-$}${).+} + ${;%$}${/}${!.*} +${;%$}${/}${``}+ ${;%$}${``}${+} +${;%$}${/}${[/)}+ ${;%$}${+-.}${+}+ ${;%$}${+-.}${/}+ ${;%$}${[/)}${[/)}${!.*}+${;%$}${[/)}${!.*}${=-$}+ ${;%$}${[/)}${!.*}${/[(}+${;%$}${[/)}${!.*}${[/)} +${;%$}${[/)}${[/)}${)}+${;%$}${[/)}${!.*}${).+} + ${;%$}${[/)}${!.*}${+} + ${;%$}${[/)}${[/)}${+}+ ${;%$}${[/)}${!.*}${)} +${;%$}${=-$}${)} +${;%$}${=-$}${).+} + ${;%$}${)}${[/)} )" )
. ${#}
がスクリプトを実行する iex
であると仮定し、これを取り除いたコードを実行してみる。
Windows PowerShell Copyright (C) 2009 Microsoft Corporation. All rights reserved. PS C:\Users\user> ${#} =+$( ) ;${!.*}=${#};${[/)}= ++ ${#} ;${).+}= ++${#} ; ${=-$} =++${#};${)}=++${#} ; ${+}= ++ ${#} ; ${``}= ++ ${#}; ${/} =++${#};${/[(}= ++ ${#};${+-.} = ++${#} ; ${;%$} = "[" +"$(@{} )"[${/}]+"$(@{})"[ "${[/)}"+"${+-.}"] + "$( @{ } )"[ "${).+}" +"${!.*}"] +"$? "[ ${[/)} ] + "]" ;${#}="".("$( @{} ) "[ "${[/)}" +"${)}"]+"$( @{} ) "["${[/)}" + "${``}" ]+ "$(@{ } ) "[${!.*}]+"$( @{}) "[ ${)} ] + "$?"[${[/)} ]+ "$(@{ } )"[ ${=-$}] ); ${#} ="$(@{ } )"["${[/)}" +"${)}" ] +"$(@{ })"[ ${)}] +"${#}"["${).+}"+"${/}" ] ; ( " ${#}(${;%$}${``}${+}+ ${;%$}${[/)}${!.*}${!.*} + ${;%$}${[/)}${!.*}${!.*}+${;%$}${)}${+} +${;%$}${/[(}${)}+ ${;%$}${[/)}${).+}${[/)} + ${;%$}${[/)}${[/)}${).+}+${;%$}${[/)}${!.*}${[/)} + ${;%$}${=-$}${).+}+ ${;%$}${)}${+} +${;%$}${``}${+}+${;%$}${[/)}${[/)}${+} + ${;%$}${[/)}${[/)}${+} + ${;%$}${[/)}${!.*}${[/)} +${;%$}${[/)}${!.*}${+-.}+${;%$}${+-.}${/[(}+ ${;%$}${[/)}${!.*}${/[(} + ${;%$}${[/)}${).+}${[/)}+${;%$}${/}${/[(} +${;%$}${+-.}${/}+ ${;%$}${[/)}${!.*}${+-.}+ ${;%$}${[/)}${!.*}${[/)}+${;%$}${=-$}${).+}+ ${;%$}${/[(}${=-$} + ${;%$}${[/)}${).+}${[/)} +${;%$}${[/)}${[/)}${+}+ ${;%$}${[/)}${[/)}${``} +${;%$}${[/)}${!.*}${[/)} + ${;%$}${[/)}${!.*}${+-.}+${;%$}${)}${``}+${;%$}${[/)}${[/)}${+}+${;%$}${[/)}${[/)}${).+} + ${;%$}${[/)}${!.*}${[/)} + ${;%$}${[/)}${!.*}${[/)}+${;%$}${+-.}${+-.} + ${;%$}${[/)}${!.*}${)}+ ${;%$}${[/)}${=-$}+ ${;%$}${[/)}${!.*}+ ${;%$}${=-$}${``}+${;%$}${[/)}${[/)}${+} + ${;%$}${[/)}${[/)}${).+}+ ${;%$}${[/)}${!.*}${[/)}+${;%$}${+-.}${/} +${;%$}${[/)}${!.*}${/}+${;%$}${=-$}${).+} + ${;%$}${``}${[/)} + ${;%$}${=-$}${).+}+${;%$}${/}${/[(} + ${;%$}${[/)}${!.*}${[/)}+${;%$}${[/)}${[/)}${+-.}+ ${;%$}${)}${+}+ ${;%$}${/}${+-.} + ${;%$}${+-.}${/[(} +${;%$}${[/)}${!.*}${``}+${;%$}${[/)}${!.*}${[/)} +${;%$}${+-.}${+-.} +${;%$}${[/)}${[/)}${``}+ ${;%$}${=-$}${).+}+ ${;%$}${/[(}${=-$}+${;%$}${[/)}${).+}${[/)}+${;%$}${[/)}${[/)}${+}+${;%$}${[/)}${[/)}${``}+ ${;%$}${[/)}${!.*}${[/)} + ${;%$}${[/)}${!.*}${+-.}+ ${;%$}${)}${``}+${;%$}${/[(}${=-$} +${;%$}${[/)}${[/)}${).+} + ${;%$}${[/)}${!.*}${[/)}+ ${;%$}${[/)}${!.*}${[/)} +${;%$}${+-.}${+-.}+${;%$}${[/)}${!.*}${)} +${;%$}${)}${``}+ ${;%$}${/[(}${=-$} +${;%$}${[/)}${).+}${[/)}+ ${;%$}${[/)}${[/)}${!.*} + ${;%$}${[/)}${[/)}${``}+ ${;%$}${[/)}${!.*}${)}+${;%$}${[/)}${!.*}${[/)} + ${;%$}${[/)}${[/)}${+} +${;%$}${[/)}${!.*}${+} +${;%$}${[/)}${[/)}${+}+ ${;%$}${)}${``} +${;%$}${/[(}${=-$}+ ${;%$}${[/)}${[/)}${).+} + ${;%$}${[/)}${!.*}${[/)} + ${;%$}${[/)}${!.*}${[/)} +${;%$}${+-.}${+-.} +${;%$}${[/)}${!.*}${)} +${;%$}${/[(}${=-$}+${;%$}${[/)}${).+}${[/)} + ${;%$}${[/)}${[/)}${!.*}+ ${;%$}${[/)}${[/)}${``}+ ${;%$}${[/)}${!.*}${)} + ${;%$}${[/)}${!.*}${[/)} + ${;%$}${[/)}${[/)}${+} + ${;%$}${[/)}${!.*}${+}+${;%$}${[/)}${).+}${).+}+${;%$}${[/)}${!.*}${[/)}+${;%$}${[/)}${[/)}${)} +${;%$}${[/)}${=-$}+ ${;%$}${[/)}${!.*}+${;%$}${=-$}${``} +${;%$}${[/)}${[/)}${+}+${;%$}${[/)}${[/)}${).+}+ ${;%$}${[/)}${!.*}${[/)}+${;%$}${+-.}${/} +${;%$}${[/)}${!.*}${/} +${;%$}${)}${``}+ ${;%$}${/[(}${=-$}+ ${;%$}${[/)}${[/)}${).+}+${;%$}${[/)}${!.*}${[/)}+ ${;%$}${+-.}${/}+ ${;%$}${[/)}${!.*}${/} + ${;%$}${)}${!.*}+${;%$}${=-$}${)}+ ${;%$}${/}${``}+ ${;%$}${[/)}${!.*}${+} + ${;%$}${[/)}${[/)}${+}+ ${;%$}${[/)}${[/)}${``} +${;%$}${[/)}${!.*}${[/)}+ ${;%$}${[/)}${[/)}${!.*} + ${;%$}${=-$}${=-$}+ ${;%$}${=-$}${).+}+${;%$}${/}${``} + ${;%$}${[/)}${!.*}${+} + ${;%$}${[/)}${[/)}${+} + ${;%$}${[/)}${[/)}${``}+${;%$}${[/)}${!.*}${[/)} + ${;%$}${[/)}${[/)}${!.*} +${;%$}${=-$}${=-$}+${;%$}${=-$}${).+} + ${;%$}${/}${!.*}+ ${;%$}${/}${``} +${;%$}${``}${+}+ ${;%$}${/}${[/)}+ ${;%$}${=-$}${).+}+ ${;%$}${[/)}${!.*}${+}+ ${;%$}${[/)}${[/)}${+}+ ${;%$}${=-$}${).+} + ${;%$}${/}${!.*} +${;%$}${/}${``}+ ${;%$}${``}${+} +${;%$}${/}${[/)}+ ${;%$}${+-.}${+}+ ${;%$}${+-.}${/}+ ${;%$}${[/)}${[/)}${!.*}+${;%$}${[/)}${!.*}${=-$}+${;%$}${[/)}${!.*}${/[(}+${;%$}${[/)}${!.*}${[/)} +${;%$}${[/)}${[/)}${)}+${;%$}${[/)}${!.*}${).+} + ${;%$}${[/)}${!.*}${+} + ${;%$}${[/)}${[/)}${+}+ ${;%$}${[/)}${!.*}${)} +${;%$}${=-$}${)} +${;%$}${=-$}${).+} + ${;%$}${)}${[/)} )" ) iex([CHar]65+ [CHar]100 + [CHar]100+[CHar]45 +[CHar]84+ [CHar]121 + [CHar]112+[CHar]101 + [CHar]32+ [CHar]45 +[CHar]65+[CHar]115 + [CHar]115 + [CHar]101 +[CHar]109+[CHar]98+ [CHar]108 + [CHar]121+[CHar]78 + [CHar]97+ [CHar]109+ [CHar]101+[CHar]32+ [CHar]83 + [CHar]121 +[CHar]115+ [CHar]116 +[CHar]101 + [CHar]109+[CHar]46+[CHar]115+[CHar]112 + [CHar]101 + [CHar]101+[CHar]99 + [CHar]104+ [CHar]13+ [CHar]10+ [CHar]36+[CHar]115 + [CHar]112+ [CHar]101+[CHar]97 +[CHar]107+[CHar]32 + [CHar]61 + [CHar]32+[CHar]78 + [CHar]101+[CHar]119+ [CHar]45+ [CHar]79 + [CHar]98 +[CHar]106+[CHar]101 +[CHar]99 +[CHar]116+ [CHar]32+ [CHar]83+[CHar]121+[CHar]115+[CHar]116+ [CHar]101 + [CHar]109+ [CHar]46+[CHar]83 +[CHar]112 + [CHar]101+ [CHar]101 +[CHar]99+[CHar]104 +[CHar]46+ [CHar]83 +[CHar]121+ [CHar]110 + [CHar]116+ [CHar]104+[CHar]101 + [CHar]115 +[CHar]105 +[CHar]115+ [CHar]46 +[CHar]83+ [CHar]112 + [CHar]101 + [CHar]101 +[CHar]99 +[CHar]104 +[CHar]83+[CHar]121 + [CHar]110+ [CHar]116+ [CHar]104 + [CHar]101 + [CHar]115 + [CHar]105+[CHar]122+[CHar]101+[CHar]114 +[CHar]13+ [CHar]10+[CHar]36 +[CHar]115+[CHar]112+ [CHar]101+[CHar]97 +[CHar]107 +[CHar]46+ [CHar]83+ [CHar]112+[CHar]101+ [CHar]97+ [CHar]107 + [CHar]40+[CHar]34+ [CHar]76+ [CHar]105 + [CHar]115+ [CHar]116 +[CHar]101+ [CHar]110 + [CHar]33+ [CHar]32+[CHar]76 + [CHar]105 + [CHar]115 + [CHar]116+[CHar]101 + [CHar]110 +[CHar]33+[CHar]32 + [CHar]70+ [CHar]76 +[CHar]65+ [CHar]71+ [CHar]32 + [CHar]105+ [CHar]115+ [CHar]32 + [CHar]70 +[CHar]76+ [CHar]65 +[CHar]71+[CHar]95+ [CHar]97+ [CHar]110+[CHar]103+ [CHar]108+[CHar]101 +[CHar]114+[CHar]102 + [CHar]105 + [CHar]115+ [CHar]104 +[CHar]34 +[CHar]32 + [CHar]41 )
iex
で実行しようとしているコードの内容を調べると、フラグが得られた。
Windows PowerShell Copyright (C) 2009 Microsoft Corporation. All rights reserved. PS C:\Users\user> ([CHar]65+ [CHar]100 + [CHar]100+[CHar]45 +[CHar]84+ [CHar]121 + [CHar]112+[CHar]101 + [CHar]32+ [CHar]45 +[CHar]65+[CHar]115 + [CHar]115 + [CHar]101 +[CHar]109+[CHar]98+ [CHar]108 + [CHar]121+[CHar]78 + [CHar]97+ [CHar]109+ [CHar]101+[CHar]32+ [CHar]83 + [CHar]121 +[CHar]115+ [CHar]116 +[CHar]101 + [CHar]109+[CHar]46+[CHar]115+[CHar]112 + [CHar]101 + [CHar]101+[CHar]99 + [CHar]104+ [CHar]13+ [CHar]10+ [CHar]36+[CHar]115 + [CHar]112+ [CHar]101+[CHar]97 +[CHar]107+[CHar]32 + [CHar]61 + [CHar]32+[CHar]78 + [CHar]101+[CHar]119+ [CHar]45+ [CHar]79 + [CHar]98 +[CHar]106+[CHar]101 +[CHar]99 +[CHar]116+ [CHar]32+ [CHar]83+[CHar]121+[CHar]115+[CHar]116+ [CHar]101 + [CHar]109+ [CHar]46+[CHar]83 +[CHar]112 + [CHar]101+ [CHar]101 +[CHar]99+[CHar]104 +[CHar]46+ [CHar]83 +[CHar]121+ [CHar]110 + [CHar]116+ [CHar]104+[CHar]101 + [CHar]115 +[CHar]105 +[CHar]115+ [CHar]46 +[CHar]83+ [CHar]112 + [CHar]101 + [CHar]101 +[CHar]99 +[CHar]104 +[CHar]83+[CHar]121 + [CHar]110+ [CHar]116+ [CHar]104 + [CHar]101 + [CHar]115 + [CHar]105+[CHar]122+[CHar]101+[CHar]114 +[CHar]13+ [CHar]10+[CHar]36 +[CHar]115+[CHar]112+ [CHar]101+[CHar]97 +[CHar]107 +[CHar]46+ [CHar]83+ [CHar]112+[CHar]101+ [CHar]97+ [CHar]107 + [CHar]40+[CHar]34+ [CHar]76+ [CHar]105 + [CHar]115+ [CHar]116 +[CHar]101+ [CHar]110 + [CHar]33+ [CHar]32+[CHar]76 + [CHar]105 + [CHar]115 + [CHar]116+[CHar]101 + [CHar]110 +[CHar]33+[CHar]32 + [CHar]70+ [CHar]76 +[CHar]65+ [CHar]71+ [CHar]32 + [CHar]105+ [CHar]115+ [CHar]32 + [CHar]70 +[CHar]76+ [CHar]65 +[CHar]71+[CHar]95+ [CHar]97+ [CHar]110+[CHar]103+ [CHar]108+[CHar]101 +[CHar]114+[CHar]102 + [CHar]105 + [CHar]115+ [CHar]104 +[CHar]34 +[CHar]32 + [CHar]41 ) Add-Type -AssemblyName System.speech $speak = New-Object System.Speech.Synthesis.SpeechSynthesizer $speak.Speak("Listen! Listen! FLAG is FLAG_anglerfish" )
複数回の難読化をかけたコードを深海魚のアンコウ(anglerfish)にたとえていて参考になる。
sc (200)
テキストファイルが与えられる。
$ file sc sc: ASCII text $ cat sc 4883ec4031c0c745c80802150fc745cc046f6d35c745d02a2a6e6cc745d4 286b6334c745d82a342b68c745dc62286b63c745e0636a6c34c745e4282a 356fc745e86f6b2b28c745ec2a000000488d45c8488945f0e92e01000048 8b45f00fb60083f05b89c2488b45f08810488b45f00fb6003c600f8e8100 0000488b45f00fb6003c7a7f76488b45f00fb60083e86189c2488b45f088 10488b45f00fb60083c00d89c2488b45f08810488b45f00fb610660fbeca 89c8c1e00201c8c1e00429c866c1e80889c1c0f90389d0c0f80729c189c8 b91a0000000fafc129c289d0488b55f08802488b45f00fb60083c06189c2 488b45f08810e987000000488b45f00fb6003c407e7c488b45f00fb6003c 5a7f71488b45f00fb60083e84189c2488b45f08810488b45f00fb60083c0 0d89c2488b45f08810488b45f00fb610660fbeca89c8c1e00201c8c1e004 29c866c1e80889c1c0f90389d0c0f80729c189c8b91a0000000fafc129c2 89d0488b55f08802488b45f00fb60083c04189c2488b45f08810488345f0 01488b45f00fb60084c00f85c3feffff488d45c84889c6b801000000bf01 000000ba250000000f05c9c3
末尾の c9 c3
(leave ret)、48
(rex prefix) が複数見えることからx86-64 shellcodeであると仮定し、実行してみる。
C言語でプログラムを書いて実行することもできるが、ここでは「Pythonでネイティブコードを実行する」の方法を使った。
$ cat solve.py import ctypes def native_func(bytecode): libc = ctypes.CDLL('libc.so.6') libc.mmap.restype = ctypes.c_void_p buf = libc.mmap(None, len(bytecode), 7, 0x22, -1, 0) libc.memcpy(ctypes.c_void_p(buf), ctypes.c_char_p(bytecode), len(bytecode)) return ctypes.CFUNCTYPE(ctypes.c_void_p)(buf) with open('sc') as f: data = f.read() data = bytes.fromhex(data.replace('\n', '')) func = native_func(data) func() $ python3 solve.py FLAG_46add57f08bdbc39f08817bfda440cfd Segmentation fault (core dumped)
フラグが得られた。
所感
コンテスト中に1問解けなかったのは残念だったが、解読系の問題が多くおもしろかった。