刷题[De1CTF 2019]SSRF Me
前置知识
本题框架是flask框架,正好python面向对象和flask框架没怎么学,借着这个好好学一下
这里我直接听mooc上北京大学陈斌老师的内容,因为讲的比较清楚,直接把他的ppt拿过来,看看就懂了


解题思路

直接给源码,得知是python,flask框架。审就完事了
代码审计
#! /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
reload(sys)
sys.setdefaultencoding('latin1')
app = Flask(__name__)
secert_key = os.urandom(16)
class Task:
def __init__(self, action, param, sign, ip):
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.mkdir(self.sandbox)
def Exec(self):
result = {}
result['code'] = 500
if (self.checkSign()):
if "scan" in self.action:
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:
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):
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", ""))
action = "scan"
return getSign(action, param)
@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())
@app.route('/')
def index():
return open("code.txt","r").read()
def scan(param):
socket.setdefaulttimeout(1)
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):
check=param.strip().lower()
if check.startswith("gopher") or check.startswith("file"):
return True
else:
return False
if __name__ == '__main__':
app.debug = False
app.run(host='0.0.0.0',port=80)
代码量不是很长,大概意思是创建了一个Task类,定义了若干个函数,利用时再剖析,三个路由
geneSign路由:
其调用了getSign函数,返回了经md5处理的值De1ta路由:
通过get方法传入param的值,在cookie中传入action和sign的值,将param通过waf函数。再用传入的参数构造一个Task类,执行Exec函数。
首先看waf函数,禁了gopher协议和file协议,这么打ssrf打不了了。
再看exec函数,大概就是先判断成功登陆,登陆成功后,读经过scan扫描的param,那么思路就出来了,如果我们传入param的值为flag.txt,并且令action里面有scan和read这两个参数,即可读取内容/路由:
根目录路由,指定了访问根目录时,会读整个源码,并定义了一些基础函数
大概思路明确了。
保证checkSign函数返回真
保证 getSign(self.action, self.param) == self.sign
即经过hashlib.md5(secert_key + param + action).hexdigest()处理
需要知道这三个字符串连接后的md5值,但是纵观源码并没有哪里有secert_key
方法一 字符串拼接
我们又发现很有意思的一点,确认action的值时,使用的是in,并非是等于号,也就是说只要read在action里即可。
因为使用的是连接符号加号(+),那么传入这两个值时
md5(secert_key + 'flag.txt' + 'readscan')
md5(secert_key + 'flag.txtread' + 'scan')
其实是相同的字符串md5(secert_keyflag.txtreadscan),经md5处理当然也相同
我们先令/geneSign?param=flag.txtread。在此页面下我们可以获得md5(secert_key + 'flag.txtread' + 'scan') 的值
再访问/De1ta路由,在其中传入cookie值和get请求即可获得对应的flag

方法二 哈希长度扩展攻击
git clone https://github.com/bwall/HashPump.git
$ apt-get install g++ libssl-dev
$ cd HashPump
$ make
$ make install
首先在kali机下安装,这里我的kali机没换国内源。。。先换国内源,然后如果有问题的话aptitude降级安装
一步一步敲命令,完成后
使用方法:
使用方法:
Input Signature 为md5(salt+message)的值
Input Data 为message内容
Input Key Length 为salt+message长度
Input Data to Add 为自定义添加

(因为代码中告诉了secert_key为16位,这里的sat看成16位的secert_key+8位的flag.txt即24位)
算出最后的值同样放在cookie中即可(\x记得换成%,即url形式)
CVE-2019-9948
Python 2.x到2.7.16中的urllib支持local_file
local_file允许远程攻击者绕过保护机制
这里是使用的 urllib.urlopen(param) 去包含的文件,所以可以直接加上文件路径 flag.txt 或 ./flag.txt 去访问,也可以使用类似的 file:///app/flag.txt 去访问,但是 file 关键字在黑名单里,可以使用 local_file 代替
如果使用 urllib2.urlopen(param) 去包含文件就必须加上 file ,否则会报 ValueError: unknown url type: /path/to/file 的错误
总结思路
- 踏实的代码审计功底
- MD5扩展攻击
- 搜索cve,拿poc打
知识点
- python代码审计
- md5扩展攻击
刷题[De1CTF 2019]SSRF Me的更多相关文章
- 刷题记录:[De1CTF 2019]SSRF Me
目录 刷题记录:[De1CTF 2019]SSRF Me 一.涉及知识点 1.MD5长度扩展攻击 2.Python 2.x - 2.7.16 urllib.fopen支持local_file导致LFI ...
- [De1CTF 2019]SSRF Me
原帖地址 : https://xz.aliyun.com/t/5927 De1CTF 2019 的一个题目总结 题目描述 直接查看页面源代码可以看到正确格式的代码 #! /usr/bin/env py ...
- [De1CTF 2019]SSRF Me-MD5长度扩展攻击&CVE-2019-9948
0x00 打开题目查看源代码,开始审计 这里贴上网上师傅的博客笔记: https://xz.aliyun.com/t/6050 #! /usr/bin/env python #encoding=utf ...
- BUUCTF | [De1CTF 2019]SSRF Me
解法一字符串拼接: 1.得到签名sign http://8fa4531c-1164-49b7-a700-70e77e6aacb7.node3.buuoj.cn/geneSign?param=flag. ...
- 刷题[GWCTF 2019]mypassword
解题思路 打开网站,登陆框.注册一个用户后再登陆 看样子是注入了,在feedback.php中发现注释 <!-- if(is_array($feedback)){ echo "< ...
- 刷题[GWCTF 2019]你的名字
解题思路 打开发现需要输入名字,猜测会有sql注入漏洞,测试一下发现单引号被过滤了,再fuzs下看看过滤了哪些 长度为1518和1519的都有过滤,测试一下,感觉不是sql注入了.那还有什么呢,考虑了 ...
- 刷题[RCTF 2019]Nextphp
前置知识 一些关于php7.4版本需知: 1.FFI扩展:ffi.cdef 其中还有这样一段话 如果ffi.cdef没有第二个参数,会在全局查找,第一个参数所声明的符号.意思就是其在不传入第二个参数时 ...
- 刷题[SUCTF 2019]CheckIn
解题思路 打开网页发现只是简单做了一个上传界面,朴实无华 上传一个php文件,发现非法后缀. 上传一个.htaccess文件,发现,爆出很重要的信息 exif_imagetype函数通过检测文件头来检 ...
- 刷题[RoarCTF 2019]Easy Java
前置知识 WEB-INF/web.xml泄露 java web工程目录结构 Servlet访问URL映射配置 由于客户端是通过URL地址访问Web服务器中的资源,所以Servlet程序若想被外界访问, ...
随机推荐
- python 复制与粘贴处理笔记
在python中用有一个模块可以用来处理剪切板复制的内容,pyperclip模块 pyperclip模块有copy()和paste()函数,分别用于向计算机的剪贴板发送文本,或从它接受文本. pype ...
- MySQL数据和索引占用空间查询
MySQL数据和索引占用空间查询 查询所有数据库占用磁盘空间大小的SQL语句 SELECT table_schema, -- 数据库名称 concat( TRUNCATE ( sum( data_le ...
- seo工程师是什么,需要什么技能?
http://www.wocaoseo.com/thread-222-1-1.html seo工程师是什么,SEO工程师是目前需求较大的一种职业,是搜索引擎营销的一种,主要是是通过网站优化技 ...
- 焦大:seo思维进化论(番外)
http://www.wocaoseo.com/thread-54-1-1.html 我已经在博客说了学seo研究算法是愚蠢的行为,但是很多人仍旧来问se的算法问题,其中最多的就是问TF-IDF算法, ...
- MySQL主从同步简单介绍&配置
介绍: 现在mysql集群基本上都是使用一主多从方式,实现读写分离(主库写.从库读).负载均衡.数据备份,以前只是使用从未配置过,今天简单配置一下! mysql主从复制是通过binary log日志实 ...
- Linux下如何知道是否有人在使坏?
在 Linux 下查看用户的行为,不仅仅是网管要做的事,也是开发人员所应该具备的基本技能之一.为什么呢?因为有时其他同事在做一些很消耗资源的事情,比如在编译大型程序,可能会导致服务器变得很慢,从而影响 ...
- 5分钟快速学会xpath定位
今天我们先来和大家说一下appium,首先教大家如何定位xpath,五分钟即可学会:例:现在我想定位下面这个登录按钮: xpath该怎么写呢? 先不管三七二十几,先写//,然后找你要定位元素最近的可以 ...
- 23种设计模式 - 数据结构(Composite - iterator - Chain of Responsibility)
其他设计模式 23种设计模式(C++) 每一种都有对应理解的相关代码示例 → Git原码 ⌨ 数据结构 Composite 动机(Motivation) 软件在某些情况下,客户代码过多依赖于对象容器复 ...
- Illegal instruction报错 c/c++
报错 # ./agent Illegal instruction# 原因 myLog(log4cplus::INFO_LOG_LEVEL, g_p_debugLog, "sendLog ip ...
- 数据结构与算法系列2 线性表 链表的分类+使用java实现链表+链表源码详解
数据结构与算法系列2.2 线性表 什么是链表? 链表是一种物理存储单元上非连续,非顺序的存储结构,数据元素的逻辑顺序是通过链表的链接次序实现的一系列节点组成,节点可以在运行时动态生成,每个节点包括两个 ...