HTB academy intro to assembly language skills assessment task 1

Hi, I hope someone can give me a hint on this.
I’m stuck, I am able to run the code that @XSSDoctor shared, but when running with loader.py the values from $rdx, the only thing I get is a red dollar sign as if it’s a shell, and then when I write any command (whoami, ls) goes back to my system prompt, and even the result of echo $? is 0, so it ran correctly.
I don’t know if my shellcode is not correctly formatted, I’m hard stuck.
I would appreciate any help, DM me if required.

1 Like

I finally figured it out! Shoutout to olliz0r from the Discord community for the hint!

Debug, and debug again, what is the value of the rdx register before the xor?

Sorry but I’m a bit confused. xor [rdx], rbx should not alter the value in rbx but directly write the xor-ed value back to the stack. Also, I tried directly yielding the control flow to the decoded shellcode by enabling stack execution when linking the binary with ld -z execstack. Unfortunately, the decoded shellcode contains plenty of register-based memory access, which leads to segfaults as most of the registers are initialized with value 0.

My approach is kinda similar to yours with the trust of task statement that decode the shellcode, by adding a loop to ‘xor’ each 8-bytes on the stack with the key in ‘rbx’.

	global _start

	section .text
_start:
	mov	rax,0xa284ee5c7cde4bd7
	push   rax
	mov rax,0x935add110510849a
	push   rax
	mov rax,0x10b29a9dab697500
	push   rax
	mov rax,0x200ce3eb0d96459a
	push   rax
	mov rax,0xe64c30e305108462
	push   rax
	mov rax,0x69cd355c7c3e0c51
	push   rax
	mov rax,0x65659a2584a185d6
	push   rax
	mov rax,0x69ff00506c6c5000
	push   rax
	mov rax,0x3127e434aa505681
	push   rax
	mov rax,0x6af2a5571e69ff48
	push   rax
	mov rax,0x6d179aaff20709e6
	push   rax
	mov rax,0x9ae3f152315bf1c9
	push   rax
	mov rax,0x373ab4bb0900179a
	push   rax
	mov rax,0x69751244059aa2a3
	push   rax
	mov rbx,0x2144d2144d2144d2
_loop_setup:
	mov rcx, 14
	lea rdx, [rsp]
_loop:
	xor [rdx], rbx
	add rdx, 8
	loop _loop
_exec_shellcode:
	call rsp
_exit:
	mov rax, 60
	mov rdi, 0
	syscall

The patched program is then linked with stack execution enable:

$ nasm -f elf64 loaded_shellcode_patched.nasm 
$ ld -z execstack -o loaded_shellcode_patched loaded_shellcode_patched.o

Unfortunately, the decoded shellcode doesn’t look good:

Dump of assembler code from 0x7fffffffe300 to 0x7fffffffe370:
   0x00007fffffffe300:	jno    0x7fffffffe2e8
   0x00007fffffffe302:	mov    $0x31c05048,%ebx
   0x00007fffffffe307:	rex.W
   0x00007fffffffe308:	rex.W push %rbx
   0x00007fffffffe30a:	and    %eax,0x66(%rdi,%rbp,4)
   0x00007fffffffe30e:	jle    0x7fffffffe326
   0x00007fffffffe310:	sbb    0x23467c7a(%rbp),%esi
   0x00007fffffffe316:	cmpsl  %es:(%rdi),%ds:(%rsi)
   0x00007fffffffe317:	mov    $0xbf264d34,%ebx
   0x00007fffffffe31c:	mov    $0x9a4c5348,%ebx
   0x00007fffffffe321:	mov    $0x77435348,%ebx
   0x00007fffffffe326:	mov    $0x4b,%dh
   0x00007fffffffe328:	push   %rbx
   0x00007fffffffe329:	adc    -0x19(%rcx),%dh
   0x00007fffffffe32c:	and    %dh,(%rsi)
   0x00007fffffffe32e:	movsxd (%rax),%edx
   0x00007fffffffe330:	rclb   %cl,-0x442dbbdf(,%rcx,2)
   0x00007fffffffe337:	rex.W add $0xc1,%al
   0x00007fffffffe33a:	or     $0x31,%cl
   0x00007fffffffe33d:	and    %rax,0x48(%rbx,%rax,4)
   0x00007fffffffe342:	(bad)
   0x00007fffffffe343:	xor    %ecx,-0x19(%rax)
   0x00007fffffffe346:	mov    %ecx,-0x50(%rax)
   0x00007fffffffe349:	shlb   $0x48,(%rcx)
   0x00007fffffffe34c:	mul    %edx
   0x00007fffffffe34e:	or     %al,%bh
   0x00007fffffffe350:	add    %rsi,0x4831ff40(%rdi)
   0x00007fffffffe357:	add    %edx,%edx
   0x00007fffffffe359:	xor    %ecx,-0x1a(%rax)
   0x00007fffffffe35c:	mov    %ecx,-0xa(%rax)
   0x00007fffffffe35f:	xor    %ecx,-0x40(%rax)
   0x00007fffffffe362:	xor    %ecx,0x5(%rax)
   0x00007fffffffe365:	nopl   0x31ff0f05(%rdx)
   0x00007fffffffe36c:	rex.W cmp $0xc0,%al
   0x00007fffffffe36f:	addl   $0x0,(%rcx)
End of assembler dump.

You can see that there is plenty of register-based memory access, which would be invalid as most of the registers are initialized with the value 0. Also jno 0x7fffffffe2e8 will be taken when yielding the control flow to the shellcode as the overflow flag in the rflags register are set to 0 by default, which will jump the control flow to a lower address in the stack with all-zero initialized values.

Given 00 00 is a valid instruction in x86_64 representing add [rax], al, the shellcode would attempt to dereference the default value 0x00 in rax after the jump which leads to a segfault. Therefore, either decode the shellcode, by adding a loop to ‘xor’ each 8-bytes on the stack with the key in ‘rbx’ is misleading, or there should be a specific environment with non-default register values where the shellcode should execute.

LOL, what a Dumbo I am. Several days stuck with the task…just because I did not understand the task properly.

So, save your time if you are stuck too.

Disassemble, loop, iterate through RDX and save all results of the looping…and then just delete 0x and join the bytes together. No switching around. Just load it, run it and you will see the value you are looking for. Its straigthforward, not a trap.

2 Likes

Brilliant! With the bswap instruction, I finally got the flag ■■■■

XXSDoctor eloquently recognized that the static (8)-byte XOR key of the 34th line in the loaded_shellcode.s file includes the following in an appropriate string: \x21\x44\xd2

The task does require that one can comprehend the purpose for controlling the instructional registers with the use of combinational circuitry as it allows the respective unit to serve as a decoder while accessing the operations of its eXclusive OR logic gates; namely, the usual calling conventions for both the base and stack instructions are applied during the execution phase throughout every cycle.

After versioning the obvious file into an ELF prior to interfacng within the GDB module, one must set a breakpoint at your custom loop directive as it would perhaps necessitate the use of the following GEF command for the completion of those instructions:

stepi 14 (perform until the #15[th] memory address)

At the 15th memory address, try the following GEF command:

info stack (copy and paste the list from the 1st to 14th hexadecimal fragment of shellcode into a text editor)

The primary issue is not with the code or its instructions rather it may be for some, like myself, with the total completion of the decoding processes in relation to the XOR key.

As it has been the case for others who have mentioned it, one should remove the hexes and load the file in this order to run the amalgamated memory addresses which contain the REX encoded flag that relies on the exclusive encryption method in rbx.

1 Like

Ok, for anyone got it to print here’s a thing you should pay attention to,
when i printed using printf - outFormat db “%llx”, 0x0a, 0x00 - i got :

<…SNIP…>
c708e2f74831c0b0
14831ff40b70148 <— notice there are 15 instead of 16
31f64889e64831d2
<…SNIP…>

this one little missing 0 got me working for a couple of hours!
turns out the hex format specifier/printf will omit the 0 at the beginning, it should be like this:

<…SNIP…>
c708e2f74831c0b0
014831ff40b70148 <— fixed
31f64889e64831d2
<…SNIP…>

then all you need to do is concatenate, and use loader.py - no need to worry about endianness,
ps: i figured out whats wrong by debugging through the loop and checking rdx every time after XORing.

2 Likes

Hi guys, I’ve been stuck on this for ages and just can’t figure it out. I’ve put in so many different shellcodes that I’ve somehow got and each of them has just left me with a blank line ($ … ). I’ve tried everything I’ve seen in this forum, at least to the extent that I understand it but nothings giving me any thing remotely close. Using the code that XSSDoctor used I’ve got shellcodes looking like “7fffffffdf50…”, “4831c05048bbe6”, etc. Any help would be amazing.

Please send me message if you got any help this assessment 1 I have been stuck on for hours and hours kinda over it now not even sure what to put in I have tried that many different things to see what its looking for

you saved my time myan!

  1. after running @XSSDoctor code with gdb use x/14gx $rsp

Tell me about it. I was not a happy camper trying to figure this one out. The XOR was not making any changes. For anyone a situation like that double check your mov rbx, 0x2144d2144d2144d2 line in your instructions. I had a typo and it was showing rax. Immediately got the flag after fixing that issue. The $rdx was showing 0x0 in gdb and it took me a while to catch on to it.

don’t try out of desperation another language it is wrong(wrong answer), follow the reading with gdb and you get the flag

took me a while to find the issue. my code in itself is pretty simple because i didn’t want to bother with printf etc., so i popped the stack in $rdx, xored, and copy/pasted the result from the xored $rdx from GEF (in Sublime Text, then get rid of the 0x and inline the whole shellcode quickly).

the code is:

...
        mov rbx,0x2144d2144d2144d2
        xor cl, cl
loop:
        pop rdx
        xor rdx, rbx
        cmp cl, 14
        js loop

the issue in my case was that by default gef/gdb DOES NOT PRINT LEADING 0s in the hex addresses… so one of the xored value was showing up as 0x14… rather than 0x014…
so ultimately one byte was missing from the shellcode, that was failing. once i’ve added the 0, the shellcode worked. dumb.

p.s.: the x taught in the module to dump hex values prints as an integer so it skips the leading zeros. use p/z instead, like in p/z $rdx.

Hi! i didn´t get what you are explaining about the 0.
Do you mean we need to add a 0 in every hex?

nah, not all.

the first two lines of my loop do 1) get the most recent value of the stack to rdx (and remove it from the stack, coz, well, pop) 2) xor the value stored in rdx with rbx and store the result back in rdx. rdx is a 8 bytes register, which means it’s represented in hex by 0x + 16 digits.

when you debug the loop and see the result of the xor in rdx, you’ll notice that there’s ONE TIME when rdx contains 15 digits instead of 16. that’s because, in that case, the leading 0 is omitted when gdb/gef represents it. so it shows something like 0x123456789012345 instead of 0x0123456789012345. the leading zero is gone. so if you manually use those data to generate your shellcode, then it’s gonna fail. the solution is to “fix” that value by adding the leading zero if you generate the shellcode manually, or to write a bit more assembly and generate the shellcode automatically through some printf :))

so TL;DR, no, not all, just for one step of the loop.

What are you suppose to do after obtaining the decoded shellcode:

4831c05048bbe671

167e66af44215348

bba723467c7ab51b

4c5348bbbf264d34

4bb677435348bb9a

10633620e7711253

48bbd244214d14d2

44214831c980c104

4889e748311f4883

c708e2f74831c0b0

014831ff40b70148

31f64889e64831d2

b21e0f054831c048

83c03c4831ff0f05

I converted it to ASCII and now I am getting gibberish

I am stuck as well…

I was able to obtain the flag. Once you get the decoded shell code, use what u learned the Shellcodes section of the module

your steps
1 correct binary editing (example at the beginning of the topic)
2 understand that Shellcode is placed in this file and we need to assemble it in parts
3 in order to assemble it part by part, we do the actions indicated above in the prompt of the action module
4 run this shell code and we will get the result