image-20200922173534698

recon:

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
Starting Nmap 7.80 ( https://nmap.org ) at 2020-09-22 02:35 EDT
Nmap scan report for laser.htb (10.10.10.201)
Host is up (0.0052s latency).

PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4 (Ubuntu Linux; protocol 2.0)
9000/tcp open cslistener?
9100/tcp open jetdirect?
1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service :
SF-Port9000-TCP:V=7.80%I=7%D=9/22%Time=5F699B53%P=x86_64-pc-linux-gnu%r(NU
SF:LL,3F,"\0\0\x18\x04\0\0\0\0\0\0\x04\0@\0\0\0\x05\0@\0\0\0\x06\0\0\x20\0
SF:\xfe\x03\0\0\0\x01\0\0\x04\x08\0\0\0\0\0\0\?\0\x01\0\0\x08\x06\0\0\0\0\
SF:0\0\0\0\0\0\0\0\0")%r(GenericLines,3F,"\0\0\x18\x04\0\0\0\0\0\0\x04\0@\
SF:0\0\0\x05\0@\0\0\0\x06\0\0\x20\0\xfe\x03\0\0\0\x01\0\0\x04\x08\0\0\0\0\
SF:0\0\?\0\x01\0\0\x08\x06\0\0\0\0\0\0\0\0\0\0\0\0\0")%r(GetRequest,3F,"\0
SF:\0\x18\x04\0\0\0\0\0\0\x04\0@\0\0\0\x05\0@\0\0\0\x06\0\0\x20\0\xfe\x03\
SF:0\0\0\x01\0\0\x04\x08\0\0\0\0\0\0\?\0\x01\0\0\x08\x06\0\0\0\0\0\0\0\0\0
SF:\0\0\0\0")%r(HTTPOptions,3F,"\0\0\x18\x04\0\0\0\0\0\0\x04\0@\0\0\0\x05\
SF:0@\0\0\0\x06\0\0\x20\0\xfe\x03\0\0\0\x01\0\0\x04\x08\0\0\0\0\0\0\?\0\x0
SF:1\0\0\x08\x06\0\0\0\0\0\0\0\0\0\0\0\0\0")%r(RTSPRequest,3F,"\0\0\x18\x0
SF:4\0\0\0\0\0\0\x04\0@\0\0\0\x05\0@\0\0\0\x06\0\0\x20\0\xfe\x03\0\0\0\x01
SF:\0\0\x04\x08\0\0\0\0\0\0\?\0\x01\0\0\x08\x06\0\0\0\0\0\0\0\0\0\0\0\0\0"
SF:)%r(RPCCheck,3F,"\0\0\x18\x04\0\0\0\0\0\0\x04\0@\0\0\0\x05\0@\0\0\0\x06
SF:\0\0\x20\0\xfe\x03\0\0\0\x01\0\0\x04\x08\0\0\0\0\0\0\?\0\x01\0\0\x08\x0
SF:6\0\0\0\0\0\0\0\0\0\0\0\0\0")%r(DNSVersionBindReqTCP,3F,"\0\0\x18\x04\0
SF:\0\0\0\0\0\x04\0@\0\0\0\x05\0@\0\0\0\x06\0\0\x20\0\xfe\x03\0\0\0\x01\0\
SF:0\x04\x08\0\0\0\0\0\0\?\0\x01\0\0\x08\x06\0\0\0\0\0\0\0\0\0\0\0\0\0")%r
SF:(DNSStatusRequestTCP,3F,"\0\0\x18\x04\0\0\0\0\0\0\x04\0@\0\0\0\x05\0@\0
SF:\0\0\x06\0\0\x20\0\xfe\x03\0\0\0\x01\0\0\x04\x08\0\0\0\0\0\0\?\0\x01\0\
SF:0\x08\x06\0\0\0\0\0\0\0\0\0\0\0\0\0")%r(Help,3F,"\0\0\x18\x04\0\0\0\0\0
SF:\0\x04\0@\0\0\0\x05\0@\0\0\0\x06\0\0\x20\0\xfe\x03\0\0\0\x01\0\0\x04\x0
SF:8\0\0\0\0\0\0\?\0\x01\0\0\x08\x06\0\0\0\0\0\0\0\0\0\0\0\0\0")%r(SSLSess
SF:ionReq,3F,"\0\0\x18\x04\0\0\0\0\0\0\x04\0@\0\0\0\x05\0@\0\0\0\x06\0\0\x
SF:20\0\xfe\x03\0\0\0\x01\0\0\x04\x08\0\0\0\0\0\0\?\0\x01\0\0\x08\x06\0\0\
SF:0\0\0\0\0\0\0\0\0\0\0")%r(TerminalServerCookie,3F,"\0\0\x18\x04\0\0\0\0
SF:\0\0\x04\0@\0\0\0\x05\0@\0\0\0\x06\0\0\x20\0\xfe\x03\0\0\0\x01\0\0\x04\
SF:x08\0\0\0\0\0\0\?\0\x01\0\0\x08\x06\0\0\0\0\0\0\0\0\0\0\0\0\0")%r(TLSSe
SF:ssionReq,3F,"\0\0\x18\x04\0\0\0\0\0\0\x04\0@\0\0\0\x05\0@\0\0\0\x06\0\0
SF:\x20\0\xfe\x03\0\0\0\x01\0\0\x04\x08\0\0\0\0\0\0\?\0\x01\0\0\x08\x06\0\
SF:0\0\0\0\0\0\0\0\0\0\0\0");
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: 1 IP address (1 host up) scanned in 21.23 seconds

入口点在9100端口,打印机服务,用这个打印机漏洞利用套件的pjl模块,可以拿到打印机上的命令执行权限,可以把queued文件下载下来,但是是一串看上去是base64加密的字符串,解码之后也没啥用,执行env之后看到LPARM:ENCRYPTION MODE=AES [CBC] 推测可能是AES的CBC模式加密,首先得找到加密用的key,执行nvram dump查看内存内容,发现最后有一串字符串:

1
2
3
laser.htb:/> nvram dump
Writing copy to nvram/laser.htb
..................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................k...e....y.....13vu94r6..643rv19u

13vu94r6..643rv19u 去掉中间两个点,正好16个字符,推测CBC加密时每个块大小为16个字符。

1
2
$ cat queued.b64 | base64 -d | wc -c
129144

然而queued文件base64解码之后129144个字符,并不是16的倍数,多了一个8

把前面八个字符给去掉(实际上这个8个字符就是文件的大小),用最开始的16个字符作为IV,13vu94r6643rv19u 作为key来解密剩下的内容

1
2
3
4
5
6
7
8
9
10
11
12
13
from Crypto.Cipher import AES
import base64, struct

with open("queued.b64",'rb') as data:
data = data.read().strip()
data = base64.b64decode(data)
size, iv, ciphertext = (data[0:8],data[8:24],data[24:])
key = '13vu94r6643rv19u'.encode()
cipher = AES.new(key, AES.MODE_CBC, iv)
decrypted = cipher.decrypt(ciphertext)
with open('decrypted','wb') as output:
output.write(decrypted)

解出来是一个pdf文件,其中有9000端口的一些关键信息,大概意思就是9000端口是个feed engine,使用gRPC 来通信

image-20200922181751438

根据以上的信息和https://www.semantics3.com/blog/a-simplified-guide-to-grpc-in-python-6c4e25f0c506/ 可以大概造出个这样的协议定义 test.proto

1
2
3
4
5
6
7
8
9
10
11
12
13
syntax = "proto2";

service Print {
rpc Feed(Content) returns (Data) {}
}

message Content {
required string data = 1;
}

message Data {
required string feed = 1;
}

然后再根据文章里说的,生成gRPC类:

1
2
3
4
$ pip install grpcio
$ pip install grpcio-tools

$ python -m grpc_tools.protoc -I. --python_out=. --grpc_python_out=. test.proto

然后就可以用这个类来与9000端口通信了

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
import sys, pickle, base64
import grpc, test_pb2, test_pb2_grpc

payload = """{
"version": "v1.0",
"title": "Printer Feed",
"home_page_url": "http://printer.laserinternal.htb/",
"feed_url": "http://printer.laserinternal.htb/feeds.json",
"items": [
{
"id": "2",
"content_text": "Queue jobs"
},
{
"id": "1",
"content_text": "Failed items"
}
]
}"""
payload = base64.b64encode(pickle.dumps(payload))
channel = grpc.insecure_channel('10.10.10.201:9000')
stub = test_pb2_grpc.PrintStub(channel)
content = test_pb2.Content(data=payload)
try:
response = stub.Feed(content, timeout=3)
print(response)
except Exception as ex:
print(ex.details())

1
2
$ python client.py 
Deadline Exceeded

很容易联想到那个feed_url参数可以用来做ssrf,在自己机器上起一个http服务,然后修改成相应的feed_url,毫无意外的收到了call_back,那么就可以用这个ssrf来探测目标机器上监听在本地的服务了

脚本省略

发现开了8983端口,查询得知是apache solr的端口,关于apache solr的相关漏洞可以在这里查到:https://github.com/veracode-research/solr-injection

尝试用最新的那个CVE-2019-17558,因为是ssrf,很自然的想到用gopher或者dict协议来发起HTTP POST请求。

脚本省略

顺利拿到一个shell,顺便拿到user.txt

提权部分:

用pspy来监控机器上的命令实时执行,发现有用sshpass来ssh到docker上执行一个脚本clear.sh

image-20200922190210862

sshpass有个很有趣的问题,具体看manual:

image-20200922214824616

所以等多一会儿就能看到真正的密码了

image-20200922185254637

用这个登陆上docker,但是有啥用呢,注意看目标host机器上的ssh配置文件最后一行:StrictHostKeyChecking no 说明ssh不会进行hostkey验证,这样的话,可以在docker上将连接再次转发回host机器自己,然后将/tmp/clear.sh劫持成自己的恶意程序,这样的话就实现了提权。

上面假设root用户将自己.ssh下用ssh-keygen生成的公钥写进了authorized_keys文件中,那么在用sshpass传递的密码验证本地sshd服务之前,会先使用自己的私钥进行验证,验证成功,然后成功执行/tmp/clear.sh (我操我自己)

相关命令省略。iox, chisel, socat, lcx, nc 都可以,萝卜青菜,各有所爱。

完。