2022/1/29复习WEB 今天看了看SSRF就是通过构造恶意URL使服务器执行恶意代码在内网中查询我们无法穿透的机器,然后再通过服务器返回到我们的主机。
今天又看了看文件包含,主要是远程文件包含,在PHP5.5以前吧,
1 file_url_fopen和file_include_fopen是打开的,也就是允许代码中包含远程php端文件。
执行远程文件包含漏洞的技巧
注意每个浏览器可能记录访问日志,要写一句话木马的话要写在User-Agent中,写在URL中都会被储存了。
或者是这样,利用PHP伪协议,来执行
2.或者是写SESSION文件
PHP中的SESSION文件用于存储SESSION数据,它是根据PHPSESSID来命名存储文件,常见路径:
/var/lib/php/sessions/sess_{PHPSESSID}
/var/lib/php/sess_{PHPSESSID}
/tmp/sess_{PHPSESSID}
/tmp/sessions/sess_{PHPSESSID}
远程文件包含漏洞检测:
(1)向目标参数指定远程 URL 发起请求,确定远程服务器是否收到相应请求,此步骤可利用前面介绍过的 Burp Collaborator 进行测试。若发起请求说明有可能存在远程请求文件,同时也可能出现 SSRF 漏洞。
(2)如果第 1 步失败,尝试提交一个不存在的 IP 地址,并确认服务器尝试连接此 IP 时是否会出现超时。
(3)若第 1 步确认访问成功或者第 2 步确认请求超时,那么按前面介绍的利用方法,尝试利用远程文件包含漏洞以作最终确认。
防御:
在php.ini中设置open_basedir将可以打开的php文件限制在指定的目录中,防止跨目录访问
或者是在php.ini中关闭
即可,避免了远程文件包含和一些伪协议执行。
下面看题
[De1CTF 2019]SSRF Me 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 from flask import Flaskfrom flask import requestimport socketimport hashlibimport urllibimport sysimport osimport jsonreload(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)): 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 @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' )
先拿到代码美化之后的代码
回到本题,阅读完代码之后可以知道getsign是用来返回md5值的,在genesign函数中赋值Action为scan
也就是说getsign的参数就是
secert_key + param + action = secert_key + “” + “scan”,我们可以对中间的param进行传参改变sign值。第一次不传param时访问geneSign得到
我们构造参数时,第一个参数action要包含read, 而param应该是文件名,第三个参数不知道,我们只能用genesign来加密,不能自己搞加密。
如果我们传参param = flag.txt,也就得到了md5(secert_key+flag.txtscan)
可以看到action = scan是用来写入的,把param对应文件路径的文件写入这个文件。也就是把flag.txt写入这个文件了
至于它的检验,scan和Read是否在action中,我们只需要修改cookie之后一同传参即可,将cookie中的action改为scanread将sign改为最后传参加密生成的md5,然后repeat即可!
下面是burpsuite操作步骤
最后这张图好好理解一下,刚才flag.txtead是为了得到read和scan的拼接,现在已经在cookie中拼接上了,在get请求中就不必重复了,只有flag.txt即可。
看到又是flask模板注入,实在受不了了,干脆把它学会
直接建立简单server之后访问127.0.0.1
可以用python语法看出,变量app是Flask实例,通过下面的方式
1 2 3 4 @app.route("/" ); def hello_world (): return "hello world!"
当客户端用get方法访问”/“时,就调用函数hello_world()就这么简单!所以我们在执行程序结果的地方看到了http请求有’/‘
上面的代码中,python内置变量__name__
的值是字符串__main__
。Flask类将这个参数作为程序名称。当然这个是可以自定义的,比如app = Flask("my-app")
如图改了名字,也就是name 的值为my-app
绑定IP和端口,默认为127.0.0.1:5000也可以自定义
1 app.run(host = "0.0.0.0", port = 80, debug = True)
0.0.0.0代表电脑所有IP, 80端口即用http协议。