Showing posts with label OTW. Show all posts
Showing posts with label OTW. Show all posts

Thursday, October 17, 2024

Wherein We Wade Through A Shellcode Shore: before the dive

 

Open Spotify > Search: 'Call it Fate, Call it Karma', by The Strokes > Play > Thank me later



Are you in the mood for some history and cool computer tales? Just lay back, enjoy the music, and hear me out.

While playing the Narnia game on OverTheWire, I hit a roadblock. I could either hack my way into advancing another level, or I could step back, take a better look at what was being presented, and learn a little bit more in the process. Ask a few questions, you know? Like why is it that...? You catch my drift.

This blogpost marks the beginning of that journey and some of what I learned while studying shellcode, its history, implications, and the tricks of the trade. Since the rabbit hole runs pretty deep, I'll be breaking this post in multiple parts. Don't worry, thoughsince real friends know C (and then break it) I'll be getting back to the C cracking series in no time. Fret not.


The Narnia game is about code injection and shellcode... But what is that?

It's essentially a small piece of code used as a payload in exploiting vulnerabilities.

It’s a means to an end: allowing attackers to exploit certain bugs, like buffer overflows, and thus alter the normal program logic (e.g., skipping a function altogether and steering the program's flow toward the attacker's purpose).

The name says it all: shellcode—spawning a shell and gaining control of the target machine to run commands at will. This was the original purpose (FYI: more modern shellcode can perform many different actions beyond just spawning a shell).

Shellcode was hugely popular in the late '90s and early 2000s when software was (even more) riddled with vulnerabilities that allowed direct code execution (see: the Morris Worm, 1988).

But shellcode is more than that. Over time, it evolved as hackers got more creative, bypassing security mechanisms, evading antivirus tools, etc. There were even competitions to cram the shortest shellcode possible into tiny bits of data. With the right perspective, anything can be fun.


Shellcode is tipically created in ASM - which allows for compact code (very important in limited memory spaces) and also gives much finer control over CPU instructions and memory manipulation.


Fun fact: Shellcode must be position-independent.

Being position-independent means that it can be executed correctly regardless of where in memory it ends up. This is crucial because we don't know where exactly it will be loaded during execution. Position-independent code (PIC) uses relative addresses, making it adaptable no matter where that code is injected.
Cool, right?

Remember that more modern systems (and even some older ones) use protections like ASLR (Address Space Layout Randomization), which randomizes memory addresses. This often drives assembly students to fits of despair when they realize they can’t follow the same memory positions as they debug code unless they turn those protections off (I’ve heard that self-inflicted hair-pulling isn't uncommon).

You might think that with all these modern protections, shellcode would be mostly irrelevant by now. Not quite.

While many classic exploits have been mitigated by security features like ASLR, DEP/NX, stack canaries, shellcode is still widely used in modern attack vectors like buffer overflow attacks, exploits in poorly configured environments, malware, and Return Oriented Programming (ROP).


A blast from the past


I'm currently reading an oldie but goodie, 'Smashing The Stack For Fun An Profit", and thoroughly enjoying it. It's fun, and if this stuff interests you at all, you should definitely check it out.

No code or exercises on this blogpost—yet. I'm still new to this and want to have something a bit more organized before diving into these waters, but another blopost should follow soon.


If you have any advice on books, courses, or other resources on this subject, please hit me up on LinkedIn, Twitter, Mastodon, or right here. I’m always open to learning more.




Thursday, October 10, 2024

Wherein We Crack A Simple Program: level Leviathan

...what in the gibson?
 


As I was about to publish my second entry in this reverse engineering series with a slightly harder program, I felt somewhat disappointed. I had promised some basic obfuscation and environment variable techniques to make the challenge more interesting, but I wanted to push it further.

While contemplating additional extra layers of fun and despair, I was reminded of an fun debugging experience from the final level of OverTheWire's Leviathan game. The level featured an executable that required a 4-digit numeric parameter which, when correct, granted access to a shell with elevated privileges - specifically, becoming the next level's user and accessing a restricted file.

Now, I promised no walkthroughs for OTW challenges, true! But let me offer this caveat: 

While what I'll explain in this blog post is (indeed) a potential solution, it's far from the most straightforward or obvious approach. 

If this was your first solution - well... you're my kind of crazy. Give me a call; my borderline-insane friends would love to meet you. No, really.

Fair warning: if you don't want a potential Leviathan solution, stop reading. But my advice? Read on, consider 'my' approach, then devise your own. Remember: the flag isn't the objective. Learning is.

Back to our executable: After solving the level, curiosity drove me to examine it with GDB. I wondered if I could spot the password in the assembly code.

And there it was, in all its hexadecimal glory:



Did you spot it? Here is our baby in all its hexadecimal glory:

0x080491da <+20>: mov DWORD PTR [ebp-0xc],0x1bd3


The flow...

Convert user input to an integer via atoi():

0x08049212 <+76>: call 0x80490a0 <atoi@plt>


Compare it with the stored password:

0x0804921a <+84>: cmp DWORD PTR [ebp-0xc],eax

0x0804921d <+87>: jne 0x804924a <main+132>


If not equal, then we have a bad password, and that's the end of that. But if we get a correct comparison, we escalate privileges:

0x080491f9 <+51>: call 0x8049050 <geteuid@plt>

0x0804922f <+105>: call 0x8049090 <setreuid@plt>


Fun? Yes. But here's where it gets interesting:



When using GDB to bypass the program, even with the correct password, privilege escalation fails. Let's compare that with the direct execution of the program, using the correct password:



...but why?

 

The Hidden Guardian: setuid and Debugging

This behavior stems from a crucial security feature in Unix-like operating systems.

 When a setuid program (one that runs with the privileges of its owner rather than the executing user) is run under a debugger, the operating system automatically drops the setuid privileges.

This protection mechanism prevents malicious users from exploiting debuggers to manipulate privileged programs. Even if you can see the password and execute the code, the debugging context itself prevents the privilege escalation from succeeding.

So, it's not just about the code we're writing and the programs we're running, but als about the environment in which we're in. The operating system itself provides layers of protection that even debuggers can't (easily) circumvent.


You hope you had fun. I learned a ton while playing these games, so I can only highly recommend them.


Or as they used to say in the good old days: two thumbs up. Way up!

Monday, September 30, 2024

Wherein We Finish The Bandit Game: OTW, part 2

 


Like the title says, I’ve finished that game, and I still maintain that I shouldn't just come here and write my step-by-step flag-finding process. That wouldn't help any reader. Not really.

Besides, in a few seconds, I'm pretty sure you could google several walkthroughs if you wanted to.

What would be the point of that, though? It’s like solving a Rubik's cube not through experimentation and discovery, but by following some ‘recipe’ online.

I'm not going to claim it would be a complete waste of time, but it wouldn't be ideal—for you. Not for me. I'd be fine.

Don’t get me wrong: I have my own write-up of how I found the various OTW flags, in some detail. I might even add it to some half-buried folder in my GitHub account. Why? Because while I was writing, I was trying to find ways to explain my thought process to others—and that’s meaningful—to me. It helped get my thoughts straight.

Instead, I want to offer some ideas, concepts, and approaches to better help you progress and learn from this game.

It is not a hard game. But that’s like saying most mathematics isn't hard. It’s a question of level and having a good grasp of the basics...


Anyway, without further ado, I’ll share a few hints, tips, and ideas to guide you through OTW’s Bandit game. Remember, these are my tips—not some unspoken truth or divine revelation. It’s what I would’ve liked to have hear before starting this trip:



1.

This game deals a lot with Linux CLI commands and basics, a few networking fundamentals and protocols (netcat, nmap, SSH, etc.), and finally some version control (Git).

2.

Take your time. Don’t rush to the flag if you can. Ask yourself questions. What do you know? What would you like to know? How could you get that information you're after? Do you understand what the problem is and what's 'holding you back'?

3.

Use the man pages, use sites, and use LLMs. Ask questions as long as you're not just looking for direct answers. It’s fine to ask how to write a specific command or to search for that command and its arguments. But it’s not okay to just paste the challenge and ask ChatGPT or some forum users how to solve it.

4.

Sometimes the end goal is less ‘fun’ than other parts. You’ve been blocked from accessing X? Oh, you found a way around that. Great! Now you have the flag. A question you might ask is: how exactly did the ‘gamemaker’ block me from accessing X? Can I find out how they did it? Can I at least catch a glimpse of that process/command/block/thinggie?

5.

Is there another way to get to the solution? Often there isn’t, but sometimes there is. Have you seen how quickly a program runs when it's feeding useless output to /dev/null versus when it’s sending everything to stdout? You might be surprised.

6.

Ask where you are. What permissions do you have right now? What can you and can’t you do? Where do you want to go? Do you need to ‘talk’ to a service? Does that service need to stay up while you're working? Is it a one-shot thing? How do you ensure that the process or program gets interrupted so that you can inject some code into it? Some challenges require you to make a program run in a (somewhat) unintended way. Try stuff.

7.

At some point you might feel annoyed, frustrated, irritated, or tired. That’s okay. Really, it is. Don’t give up. Are there any hints from the gamemakers? 

'Go check SSH?'

Alright, then go check it. Stop what you're doing (trying to find the flag at all costs) and go read about SSH. I'm not even kidding; it’s really cool to know more about SSH. Check the man page. Think of all the things you could do with its arguments. Is there anything you’d like to try or test? Test it. Try it. Did it work? Why? Why not? Ask an LLM or another person (a forum, etc.) how to use that parameter, and so on. That leads nicely into the next tip.

8.

Step back from a challenge if you're not seeing the answer right now. I’m sure you're not doing this game to get job X. At least not tomorrow. Take your time. Think about other stuff, then come back to the ‘problem’ at hand. In another life, I was a theater director and acting teacher. A student once asked me, "How do I act?" I told her to orbit around her object of desire. I took a lighter and got it so close to my face that I couldn’t see it anymore. I told her that might be too much, but that she could still perhaps learn from it (she could touch it, at least. That's something). 

Stand back from it. Further back until you can't see it anymore. Now you have to imagine the lighter, perhaps think of what you'd like to check the next time you get closer. 

You get my drift. This stuff isn’t rocket science. Don’t just stare at a problem, all sweaty, until your eyes bleed. Take a break. Walk away, look again, look away, look closer, and spin it around.

9.

Remember, this isn’t just for fun. It’s also for learning (but that is fun, right?). Again, take time to learn these tools, and above all, take time to learn how they work—their protocols, how they communicate, what you need to set up for them to work at all, etc.

10.

Remember when I told you to look beyond the problem and try different things? I’m interested in Reverse Engineering. You can bet your breeches I used radare2, created objdumps and other tools to inspect binaries and programs created by the gamemakers. Not necessarily to find the flag, but to understand what makes those programs tick—why they do what they do.


Take your time, one moment at a time, and have fun. If it stops being fun, that’s okay too. The internet is filled with games and learning tools.
Go find another one that strikes your fancy.

Often it's not the game, it's your perspective on the game. 

As I explained in part one, I got hacked while navigating my way through lvl.20, and I can tell you that I learned more from that interaction and the hours of study that followed than perhaps in 10 or so levels of Bandit combined.

That's it. I'm going to play Leviathan.


The world’s your oyster—or something. 

Saturday, September 28, 2024

Wherein We Get Hacked And Learn In The Process: OTW, part 1




For the past couple of days, I've been playing around with OverTheWire (OTW), particularly the Bandit game. And so it was, I was having my fun and going through each level, mostly reviewing stuff I know about linux or networks, but also learning quite a bit.

Upon reaching lvl 20 I was having a bit more trouble, since I was making a mess for myself in establishing a listening port and so on (I truly don't want to give spoilers or too much... see below)


Not only are these the rules, but I also agree with them. I really really think that if you are going to play these games, you should steer clear of reading spoilers, or walkthroughs. Also, if you want to write about these challenges, you can do it in an interesting fashion, that can help other players, giving them hints, or neat ideas instead of spoon-feeding them answers.

So, I won't tell you how I solved lvl 20. But I'll tell you what happened to me while I was on that level.

You know the saying 'a picture is worth a thousand words'? Well, how about a picture of words? Is the effect multiplicative? Here's the pic:


It's a bit messy, because we were using the command line in tmux as a means of communication within the terminal: which isn't its intended purpose, but still, I think you can follow the brief conversation.

Moments before, I was baffled when I noticed someone taking control of my tmux session. I closed the session, re-opened it and awaited for a reply. And there it was, with a friendly 'hello :)'. I would have started with 'Wake up, Neo...' myself...


...but that might just be my age speaking.


So, conversation friendliness aside, let us figure out together what happened here.

The other user was not only kind, but right in the way they explained to me how I could find out about the 'intrusion' method:

man tmux

That's it, really. Just read the fine manual. And so I did, taking the time to learn a couple of new things instead of just skimming it again.

One of the things that I learned is that you can scan for existing sessions, by listing them:

tmux list-sessions

or

tmux ls

This will show you current sessions and their names.

You can then jump (or attach, really) to that session. Let's say there's a session named my_session open. You could then:

tmux attach-session -t my_session

And yes. It's that simple. You are now sharing the same session as the user that created and is using it.

Try creating a couple of sessions. Create a tmux session, then exit it (Ctrl+D works).

The default name for a tmux session will be called '0'. Just that.

So, you could also, arguably, try to connect to a session automatically as well. Spamming that name until you find it, just to catch someone unawares, with:
while :; do tmux attach-session -t 0; sleep 1; done



Note: Don't do this for long. Avoid spamming the server that's granting us free access for learning. I did it for a couple of seconds, just to test stuff out,and showcase it to you. Remember to stop that loop asap (ctrl-C).

So what's happening in that image?
I have two sessions in level bandit1, and in one I'm running this loop, while in the other I simply typed 'tmux' twice, automatically entering a default tmux session, called '0'.
On both occasions, both sessions entered the same tmux session, which I'll showcase here, but with a specifically named session called my_session:


Upper left corner: my original tmux session (my_session)
Lower right corner: the session I used to jump into my_session

Whatever one user writes, the other one will see.

Test it out. You don't even have to enter OTW. You can try it on your own local machine, with two different terminals.

If you don't know, OTW makes you log into as a different user per level (usually). This means that everyone connected to that server, on that level, will have the same name. This rather interesting, and got me thinking. We're using the same users, but different terminals. Hold that thought. We'll get back to that in a second. Let's first find a way to harden our virtual tmux terminal as to not get interrupted while we're playing OTW, shall we? You're free not to do it. After all, it can be a great way to make friends. Very old school too, if I might say so myself.

Ok, so how do you 'strengthen' your tmux session, making it much harder for the general user to see what your session is?

You need to create a tmux socket and create your session through that socket.
OTW protects its filesystem, and we, as users, are only allowed to create files within the /tmp folder. So we do that. We create a socket and connect through it:

tmux -S /tmp/my_wonderful_new_secretive_socket new -s my_session_name

Any other user now trying to list all active tmux sessions won't see yours, since they'll only be able to see the default sessions.

But couldn't they simply go through all files in /tmp?

They could, but OTW has that folder protected:

There's a sticky bit there (t) ensuring that users can only modify files that they own. Also, 'r' is missing from others, meaning that they cannot read that folder.

This makes it a bit harder to simply scan the folder and start checking out stuff.

"But wait!" you say. "Couldn't we just set restrictive permissions on our own socket?"

We can, yeah. But remember that all users on this levels have the same name as we do. So, they're basically the same user.


We are, in fact, using some mild security through obscurity, and defending our tmux socket (and therefore session) from our other selves (I'll give some info on security through obscurity in another blog post).

Very Pessoesque... or is it the other way around?

Anyway, there we go. Good job at protecting yourself from your other selves!

We can now run our tmux sessions in (relative) peace. We have erected a fence that will keep away the overwhelming majority of attacks.

Remember, though, when we were looking at the rules?

- don't annoy other players

Did they meant this tmux trick? How could we possibly annoy other players?

That got me thinking.

We're all the same user, basically, but we're connecting from different terminals devices, right? Tmux would be a virtual terminal, but we're initially connecting from some other terminal.


Ok, let's see what's my current terminal:


Aha, interesting. And, just for our own pleasure, what's our virtual terminal device when inside our now (highly-amazing and protected) tmux session?


Also interesting. We can also see what permissions are set on our terminals

Try to do ls -hal /dev/pts/40

Interesting... you can see that we have writing permission if we are the user.
But, everyone in this level is bandit1, so we can just do

who


This is a list of all visible learners and their respective levels/users.

So, what's stopping us from quoting The Matrix? Nothing, other than being a nuisance. So, let's open a second session. And let's just flex our age and good taste in cinema onto our own selves in another virtual reality.
Let's also try to reply, with a caveat: we've done 'chmod 000' to our original pseudo-terminal device. Look at the result. It's interesting.


You might be wondering how we're able to continue using our terminal when we've removed all permissions, even for the owner... Good point!

 The key is that our current process already has the terminal open and maintains its file descriptors. This allows us to continue reading from and writing to the terminal as usual.

However, any new attempts to access the terminal device file will fail.
For example, if we try to send an echo message to our terminal using:

echo "Hi, guy!" > /dev/pts/40

...it won't work. 

But we can still do:

echo "Hi, guy!" normally in our current session.

Also interesting!

This showcases a bit how Unix-like systems handle file descriptors and permissions. That's also food for thougth and another day's snack.

I'll be writing more about my OTW playtime ('part 1' was a giveaway, wasn't it?). I'll share ideas, insights and stuff I find interesting, but not walkthroughs or spoilers.

Finally, I'd like to extend a thank you to the nameless 'hacker' with whom I had a pleasant, albeit short, conversation. That romp got me into a learning marathon which has been super fun.

Have fun, enter The Matrix, and behave!

SUDO INIT 6: Rebooting Your C Journey

                                                                  Yeah, let's do just that. So grab some popcorn and lean back.   I'...