Welcome everyone!
I am going to share pwn.college CTF write-ups!
This blog-serie will teach you about assembly instructions with the combination of pwntools library. You will expand your Assembly coding skills with the help of these challenges.
Let's get started
Level 1
Welcome to ASMLevel1
==================================================
To interact with any level you will send raw bytes over stdin to this program.
To efficiently solve these problems, first run it once to see what you need
then craft, assemble, and pipe your bytes to this program.
In this level you will be working with registers. You will be asked to modify
or read from registers_use.
In this level you will work with registers_use! Please set the following:
* rdi = 0x1337
Please give me your assembly in bytes (up to 0x1000 bytes):
Solution
--------------------------------------------------------------------------------------
In order to solve this challenge, we need to consider to write "* rdi, 0x1337" in to this file
We can use pwntools to fix this issue:
It is really simple to code "mov rdi, 0x1337" into our file.
In [1]: import pwn
In [2]: pwn.context.update(arch="amd64")
In [3]: process = pwn.process("/challenge/run")
[x] Starting local process '/challenge/run'
[+] Starting local process '/challenge/run': pid 16174
In [4]: process.write(pwn.asm("mov rdi, 0x1337"))
In [5]: print(process.readallS)
In [6]: print(process.readallS())
1. We considered this file as amd64
2. In order to parse this file, we should get the process ID
3. When we have parsed, now we can write our code "mov rd, 0x1337"
4. after that, just run the file.
The flag: pwn.college{wUq-SZ2pI8PzOngxTUggABzrET-.0FN5EDLxUjNyEzW}
Level 2
Welcome to ASMLevel2
==================================================
To interact with any level you will send raw bytes over stdin to this program.
To efficiently solve these problems, first run it once to see what you need
then craft, assemble, and pipe your bytes to this program.
In this level you will be working with registers. You will be asked to modify
or read from registers_use.
We will now set some values in memory dynamically before each run. On each run
the values will change. This means you will need to do some type of formulaic
operation with registers_use. We will tell you which registers_use are set beforehand
and where you should put the result. In most cases, its rax.
Many instructions exist in x86 that allow you to do all the normal
math operations on registers_use and memory. For shorthand, when we say
A += B, it really means, A = A + B. Here are some useful instructions:
add reg1, reg2 <=> reg1 += reg2
sub reg1, reg2 <=> reg1 -= reg2
imul reg1, reg2 <=> reg1 *= reg2
div is a littler harder, we will discuss it later.
Note: all 'regX' can be replaced by a constant or memory location
Do the following:
* add 0x331337 to rdi
We will now set the following in preparation for your code:
rdi = 0x351
Solution
----------------------------------------------------------------------------------------------------------------------------------
1. in order to solve this problem, we can use RAX register to store 0x13337
2. The question is quite simple we just need to use add instruction
.code
mov rax, 0x331337
add rdi, rax
And we solved this question.
Flag: pwn.college{QvjyJnljKvDhgH8llaoSe_8eW8V.0VN5EDLxUjNyEzW}
------------------------------------------------------------------------------------------------------------------------------------
Level 3
Question
--------------------------------------------------------------------------------------------
Welcome to ASMLevel3
==================================================
To interact with any level you will send raw bytes over stdin to this program.
To efficiently solve these problems, first run it once to see what you need
then craft, assemble, and pipe your bytes to this program.
In this level you will be working with registers. You will be asked to modify
or read from registers_use.
We will now set some values in memory dynamically before each run. On each run
the values will change. This means you will need to do some type of formulaic
operation with registers_use. We will tell you which registers_use are set beforehand
and where you should put the result. In most cases, its rax.
Using your new knowledge, please compute the following:
f(x) = mx + b, where:
m = rdi
x = rsi
b = rdx
Place the value into rax given the above.
We will now set the following in preparation for your code:
rdi = 0x2aa
rsi = 0x1bb3
rdx = 0x229b
Please give me your assembly in bytes (up to 0x1000 bytes):
Solution
---------------------------------------------------------------------------------------------------------------------------------
In [45]: import pwn
In [46]: pwn.context.update(arch="amd64")
In [47]: process = pwn.process("/challenge/run")
[x] Starting local process '/challenge/run'
[+] Starting local process '/challenge/run': pid 13257
In [48]: process.write(pwn.asm("mov rax, rdi; imul rax, rsi; add rax, rdx"))
The flag : pwn.college{gChn_M0Wb8kfByI2dRrAdrQAWN0.0lN5EDLxUjNyEzW}
-----------------------------------------------------------------------------------------------------------------------------
Level 4
Question
-------------------------------------------------------------------------------------
Welcome to ASMLevel4
==================================================
To interact with any level you will send raw bytes over stdin to this program.
To efficiently solve these problems, first run it once to see what you need
then craft, assemble, and pipe your bytes to this program.
In this level you will be working with registers. You will be asked to modify
or read from registers_use.
We will now set some values in memory dynamically before each run. On each run
the values will change. This means you will need to do some type of formulaic
operation with registers_use. We will tell you which registers_use are set beforehand
and where you should put the result. In most cases, its rax.
Recall division in x86 is more special than in normal math. Math in here is
called integer math. This means everything, as it is now, is in the realm
of whole looking numbers. As an example:
10 / 3 = 3 in integer math. Why? Because 3.33 gets rounded down to an integer.
The relevant instructions for this level are:
mov rax, reg1; div reg2
Notice: to use this instruction you need to first load rax with the desired register you intended to be the divided. Then run div reg2, where reg2 is the divisor. This
results in:
rax = rdi / rsi; rdx = remainder
The quotient is placed in rax, the remainder is placed in rdx.
Please compute the following:
speed = distance / time, where:
distance = rdi
time = rsi
Place the value of speed into rax given the above.
We will now set the following in preparation for your code:
rdi = 0x170c
rsi = 0x14
Please give me your assembly in bytes (up to 0x1000 bytes):
Solution
------------------------------------------------------------------------------------
In order to solve this problem:
we can just instructions which help us to compute the speed.
1. We ought to load the distance into "rax"
mov rax, rdi
2. we should store time into "rbx"
mov rbx, rsi
3. we just need to clear "rdx" (remainder)
xor rdx, rdx
4. And now, we can divide rax by rbx, result in rax
div rbx
code:
mov rax, rdi
mov rbx, rsi
xor rdx, rdx
div rbx
[+] import pwn
[+] pwn.context.update("arch=amd64")
[+] process.write(pwn.asm("""
mov rax, rdi
mov rbx, rsi
xor rdx, rdx
div rbx"""))
[+] print(process.recvallS())
The flag: pwn.college{cC2N2Ye88oqb5Y4HgkRwxWZM2XC.01N5EDLxUjNyEzW}
--------------------------------------------------------------------------------------------------------------------------------
Level 5
Question
----------------------------------------------------------------------------------------------------------------------------------
Welcome to ASMLevel5
==================================================
To interact with any level you will send raw bytes over stdin to this program.
To efficiently solve these problems, first run it once to see what you need
then craft, assemble, and pipe your bytes to this program.
In this level you will be working with registers. You will be asked to modify
or read from registers_use.
We will now set some values in memory dynamically before each run. On each run
the values will change. This means you will need to do some type of formulaic
operation with registers_use. We will tell you which registers_use are set beforehand
and where you should put the result. In most cases, its rax.
Modulo in assembly is another interesting concept! x86 allows you to get the
remainder after doing a division on something. For instance:
10 / 3 -> remainder = 1
You can get the remainder of a division using the instructions introduced earlier
through the div instruction.
In most programming languages we refer to mod with the symbol '%'.
Please compute the following:
rdi % rsi
Place the value in rax.
We will now set the following in preparation for your code:
rdi = 0x3355c0bd
rsi = 0xf
Please give me your assembly in bytes (up to 0x1000 bytes):
Solution
-----------------------------------------------------------------------------------
In order to solve this problem, we need to do modulo operation
1. we should store rdi into rax register to make it temporarily
mov rax, rdi
2. We should clean edx --> make it 0
mov edx, 0
3. divide rax by rsi, storing quotient in rax and remainder in edx
div rsi
3. store the divisor into rax to got the result.
mov rax, rdx
------------------------------------------------------------------------------
In [6]: import pwn
In [7]: pwn.context.update(arch="amd64")
In [8]: process = pwn.process("/challenge/run")
[x] Starting local process '/challenge/run'
[+] Starting local process '/challenge/run': pid 4341
In [9]: process.write(pwn.asm("""
...: mov rax, rdi
...: mov edx, 0
...: div rsi
...: mov rax, rdx"""))
The flag: pwn.college{sdQCoxpSKhsJOxKLqLi5IF0jDi1.0FO5EDLxUjNyEzW}
----------------------------------------------------------------------------------------------------------------------------------
Stay tuned! More levels, and more techniques will be appeared in my blog-post
There are 23 levels.