前置知识

本题框架是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类,定义了若干个函数,利用时再剖析,三个路由

  1. geneSign路由:

    其调用了getSign函数,返回了经md5处理的值

  2. De1ta路由:

    通过get方法传入param的值,在cookie中传入action和sign的值,将param通过waf函数。再用传入的参数构造一个Task类,执行Exec函数。

    首先看waf函数,禁了gopher协议和file协议,这么打ssrf打不了了。

    再看exec函数,大概就是先判断成功登陆,登陆成功后,读经过scan扫描的param,那么思路就出来了,如果我们传入param的值为flag.txt,并且令action里面有scan和read这两个参数,即可读取内容

  3. /路由:

    根目录路由,指定了访问根目录时,会读整个源码,并定义了一些基础函数

大概思路明确了。

保证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

方法二 哈希长度扩展攻击

需要使用工具HashPump

原理见此篇

github源码

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允许远程攻击者绕过保护机制

exp

这里是使用的 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的更多相关文章

  1. 刷题记录:[De1CTF 2019]SSRF Me

    目录 刷题记录:[De1CTF 2019]SSRF Me 一.涉及知识点 1.MD5长度扩展攻击 2.Python 2.x - 2.7.16 urllib.fopen支持local_file导致LFI ...

  2. [De1CTF 2019]SSRF Me

    原帖地址 : https://xz.aliyun.com/t/5927 De1CTF 2019 的一个题目总结 题目描述 直接查看页面源代码可以看到正确格式的代码 #! /usr/bin/env py ...

  3. [De1CTF 2019]SSRF Me-MD5长度扩展攻击&CVE-2019-9948

    0x00 打开题目查看源代码,开始审计 这里贴上网上师傅的博客笔记: https://xz.aliyun.com/t/6050 #! /usr/bin/env python #encoding=utf ...

  4. BUUCTF | [De1CTF 2019]SSRF Me

    解法一字符串拼接: 1.得到签名sign http://8fa4531c-1164-49b7-a700-70e77e6aacb7.node3.buuoj.cn/geneSign?param=flag. ...

  5. 刷题[GWCTF 2019]mypassword

    解题思路 打开网站,登陆框.注册一个用户后再登陆 看样子是注入了,在feedback.php中发现注释 <!-- if(is_array($feedback)){ echo "< ...

  6. 刷题[GWCTF 2019]你的名字

    解题思路 打开发现需要输入名字,猜测会有sql注入漏洞,测试一下发现单引号被过滤了,再fuzs下看看过滤了哪些 长度为1518和1519的都有过滤,测试一下,感觉不是sql注入了.那还有什么呢,考虑了 ...

  7. 刷题[RCTF 2019]Nextphp

    前置知识 一些关于php7.4版本需知: 1.FFI扩展:ffi.cdef 其中还有这样一段话 如果ffi.cdef没有第二个参数,会在全局查找,第一个参数所声明的符号.意思就是其在不传入第二个参数时 ...

  8. 刷题[SUCTF 2019]CheckIn

    解题思路 打开网页发现只是简单做了一个上传界面,朴实无华 上传一个php文件,发现非法后缀. 上传一个.htaccess文件,发现,爆出很重要的信息 exif_imagetype函数通过检测文件头来检 ...

  9. 刷题[RoarCTF 2019]Easy Java

    前置知识 WEB-INF/web.xml泄露 java web工程目录结构 Servlet访问URL映射配置 由于客户端是通过URL地址访问Web服务器中的资源,所以Servlet程序若想被外界访问, ...

随机推荐

  1. python 复制与粘贴处理笔记

    在python中用有一个模块可以用来处理剪切板复制的内容,pyperclip模块 pyperclip模块有copy()和paste()函数,分别用于向计算机的剪贴板发送文本,或从它接受文本. pype ...

  2. MySQL数据和索引占用空间查询

    MySQL数据和索引占用空间查询 查询所有数据库占用磁盘空间大小的SQL语句 SELECT table_schema, -- 数据库名称 concat( TRUNCATE ( sum( data_le ...

  3. seo工程师是什么,需要什么技能?

    http://www.wocaoseo.com/thread-222-1-1.html      seo工程师是什么,SEO工程师是目前需求较大的一种职业,是搜索引擎营销的一种,主要是是通过网站优化技 ...

  4. 焦大:seo思维进化论(番外)

    http://www.wocaoseo.com/thread-54-1-1.html 我已经在博客说了学seo研究算法是愚蠢的行为,但是很多人仍旧来问se的算法问题,其中最多的就是问TF-IDF算法, ...

  5. MySQL主从同步简单介绍&配置

    介绍: 现在mysql集群基本上都是使用一主多从方式,实现读写分离(主库写.从库读).负载均衡.数据备份,以前只是使用从未配置过,今天简单配置一下! mysql主从复制是通过binary log日志实 ...

  6. Linux下如何知道是否有人在使坏?

    在 Linux 下查看用户的行为,不仅仅是网管要做的事,也是开发人员所应该具备的基本技能之一.为什么呢?因为有时其他同事在做一些很消耗资源的事情,比如在编译大型程序,可能会导致服务器变得很慢,从而影响 ...

  7. 5分钟快速学会xpath定位

    今天我们先来和大家说一下appium,首先教大家如何定位xpath,五分钟即可学会:例:现在我想定位下面这个登录按钮: xpath该怎么写呢? 先不管三七二十几,先写//,然后找你要定位元素最近的可以 ...

  8. 23种设计模式 - 数据结构(Composite - iterator - Chain of Responsibility)

    其他设计模式 23种设计模式(C++) 每一种都有对应理解的相关代码示例 → Git原码 ⌨ 数据结构 Composite 动机(Motivation) 软件在某些情况下,客户代码过多依赖于对象容器复 ...

  9. Illegal instruction报错 c/c++

    报错 # ./agent Illegal instruction# 原因 myLog(log4cplus::INFO_LOG_LEVEL, g_p_debugLog, "sendLog ip ...

  10. 数据结构与算法系列2 线性表 链表的分类+使用java实现链表+链表源码详解

    数据结构与算法系列2.2 线性表 什么是链表? 链表是一种物理存储单元上非连续,非顺序的存储结构,数据元素的逻辑顺序是通过链表的链接次序实现的一系列节点组成,节点可以在运行时动态生成,每个节点包括两个 ...