avatarEsteban Thilliez

Free AI web copilot to create summaries, insights and extended knowledge, download it at here

6344

Abstract

lass="hljs-keyword">Get</span>-EventLog -logname security -InstanceId <span class="hljs-number">4720</span> | <span class="hljs-keyword">Select</span>-<span class="hljs-type">Object</span> *</pre></div><figure id="9247"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*1ogBlqZ-7dNeDpNg7baIUw.png"><figcaption></figcaption></figure><p id="fab0">Our initial assumption was accurate. Now, let’s list the privileges held by the <b><i>‘apt’ </i></b>user. Since we already know this user belongs to the Administrator group, we can confirm this by enumerating the admin group.</p><div id="0989"><pre>net localgroup Administrators</pre></div><figure id="31eb"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*n8AmAAO-wgl9guGrSdE1PQ.png"><figcaption></figcaption></figure><p id="2be9">However, the privileges held by the user <b><i>‘apt’</i></b> remain uncertain. To determine their access level, we will employ the Sysinternals tool called <b><i><a href="https://learn.microsoft.com/en-us/sysinternals/downloads/accesschk">accesschk</a>,’</i></b> which will assist us in identifying the extent of access granted to the ‘apt’ user. Go to the respective folder and this file with the below command attribute.</p><div id="f085"><pre>.\accesschk64<span class="hljs-selector-class">.exe</span> apt -<span class="hljs-selector-tag">a</span> *</pre></div><figure id="9f6f"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*kHHnzdbij_wQaZXIosY8sg.png"><figcaption></figcaption></figure><p id="7afb">Indeed, it’s confirmed that the user ‘apt’ possesses full privileges within the operating system. Our next step is to identify any active sessions associated with this user. To acquire this information, we can leverage system commands, Sysinternals tools, or even examine event logs. For now, we’ll opt for the Sysinternals tool ‘<a href="https://learn.microsoft.com/en-us/sysinternals/downloads/psloggedon">PsLoggedon</a>,’ which will help us determine any active login sessions.</p><figure id="7a36"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*SFoW2OOgM7DZZyVHPuDfSw.png"><figcaption></figcaption></figure><p id="e60d">This observation reveals that the user ‘apt’ has logged into the victim machine through system shares. To determine the origin of this connection, we can utilize the ‘net’ command to gather more information.</p><div id="d661"><pre>net session</pre></div><figure id="9ac1"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*JApyNvTUPHprvRSnyaJE6A.png"><figcaption></figcaption></figure><p id="0b6d">The observation indicates that the attacker’s machine is identified as <b><i>192.168.0.104</i></b>, and the connection to the victim’s machine remains active, suggesting that the attacker is currently on that system.</p><h1 id="0006">Process and Service Information</h1><p id="3547">Now, let’s extract valuable information from processes and services, as critical data is often concealed there. To gather process information, we have two PowerShell cmdlets at our disposal: ‘Get-Process’ and ‘Get-WmiObject Win32_Process.’ I recommend using ‘WmiObject’ because it provides more comprehensive data compared to the first cmdlet. We will retrieve a list of processes running at the time of the investigation.</p><div id="54a8"><pre><span class="hljs-keyword">Get</span>-WmiObject -<span class="hljs-keyword">Class</span> Win32_Process | <span class="hljs-keyword">select</span> ProcessName, ProcessId,CommandLine</pre></div><figure id="ea4e"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*okLiTkQMzF-ji_193xAgCg.png"><figcaption></figcaption></figure><p id="b190">Numerous processes are running, making it challenging to identify anomalies. However, given that user <b><i>VictimA</i></b> has been compromised, we should focus on processes initiated by this user.</p><div id="cca5"><pre>Get-WmiObject -Class Win32_Process | <span class="hljs-built_in">where</span> { <span class="hljs-variable">$_</span>.GetOwner().User -eq <span class="hljs-string">"VictimA"</span> } | <span class="hljs-keyword">select</span> ProcessId, Name, CommandLine</pre></div><figure id="4972"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*sh5NIGAVwx9SSsyg5ED1bg.png"><figcaption></figcaption></figure><p id="66f7">We noticed that some processes initiated by user <b><i>VictimA</i></b> appear suspicious based on their command lines. Let’s investigate the parent-child relationships for these processes using its Process ID.</p><div id="3dd1"><pre><span class="hljs-keyword">Get</span>-WmiObject -<span class="hljs-keyword">Class</span> Win32_Process | <span class="hljs-keyword">where</span> processid -<span class="hljs-keyword">In</span> <span class="hljs-number">7036</span>,<span class="hljs-number">5892</span>,<span class="hljs-number">5776</span>,<span class="hljs-number">9112</span>,<span class="hljs-number">7912</span>,<span class="hljs-number">460</span>,<span class="hljs-number">8864</span> | <span class="hljs-keyword">select</span> ParentProcessId,ProcessId, Name, CommandLine</pre></div><figure id="1b1a"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*5CeYdOtVvcy4bDPKdmxXbA.png"><figcaption></figcaption></figure><p id="ddaa">It has been observed that the <b><i>‘ad.bat’</i></b> file executed a PowerShell command. The purpose of this command was to download a PowerShell script and run it, specifying an IP address and port number as attributes. This suggests that the PowerShell script was designed to establish a reverse connection as part of an attack. The reference image is given from Process Explorer.</p><figure id="aaaa"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*fNdvmFTnbrtYE9MBTCAvdQ.png"><figcaption></figcaption></figure><p id="c8d3">Now that we have collected a significant amount of information about the suspicious processes, let’s shift our focus to the services, where we might find valuable insights. We will gather a list of all actively running services.</p><div id="6cfd"><pre>Get-WmiObject -<span class="hljs-keyword">class</span> <span class="hljs-title class_">Win32_service</span> |<span class="hljs-title">where</span> <span class="hljs-title">State</span> -<span class="hljs-title">eq</span> '<span class="hljs-title">Running</span>'| <span class="hljs

Options

-title">select</span> <span class="hljs-title">name</span>,<span class="hljs-type">processid</span>,<span class="hljs-type">status</span>,<span class="hljs-type">started</span>,<span class="hljs-type">state</span>,<span class="hljs-type">pathname</span></pre></div><figure id="1a9a"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*WVIZinER8JAbBjd-6vzfgg.png"><figcaption></figcaption></figure><p id="7bd7">No suspicious findings so far, but I’d like to take a closer look at the running services associated with the Process IDs we identified during our process investigation.</p><div id="2ff9"><pre>Get-WmiObject -<span class="hljs-keyword">class</span> <span class="hljs-title class_">Win32_service</span> |<span class="hljs-title">where</span> <span class="hljs-title">State</span> -<span class="hljs-title">eq</span> '<span class="hljs-title">Running</span>' |<span class="hljs-title">where</span> <span class="hljs-title">processid</span> -<span class="hljs-title">In</span> 7036,<span class="hljs-type">5892</span>,<span class="hljs-type">5776</span>,<span class="hljs-type">9112</span>,<span class="hljs-type">7912</span>,<span class="hljs-type">460</span>,<span class="hljs-type">8864|</span> <span class="hljs-title">select</span> <span class="hljs-title">name</span>,<span class="hljs-type">processid</span>,<span class="hljs-type">status</span>,<span class="hljs-type">started</span>,<span class="hljs-type">state</span>,<span class="hljs-type">pathname</span></pre></div><figure id="4c35"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*6CV3yOovqZM7JUBwaHnxYA.png"><figcaption></figcaption></figure><p id="49a9">Nothing suspicious was observed!!</p><h1 id="7870">Network Information</h1><p id="f2ac">As we’re aware of the reverse connection, our next step is to confirm its presence or establishment. To achieve this, we will utilize the <b><i>‘netstat</i></b>’ utility. Our first action is to retrieve a list of all connections.</p><figure id="786e"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*Ap9HOX5ljV59a3JvaZHSVQ.png"><figcaption></figcaption></figure><p id="11b0">Now, we’ll inspect the established connections and identify their owners. In our particular instance, we noted a connection on port 4444, and it’s associated with PowerShell, which is indicated by the PID 7912. This confirmation implies that a Command and Control session has been established on <b><i>192.168.0.108</i></b>.</p><figure id="0027"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*z-wRQ1UG_jCLSdxaYQPCdw.png"><figcaption></figcaption></figure><p id="b7dd">We’ll now examine the nature of communication between the compromised machine and the C2C server, which typically functions as a Master-Slave relationship. To inspect this interaction, we’ll employ Wireshark</p><figure id="5026"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*a_g9T6ZW98cMgq_iPdOznA.png"><figcaption></figcaption></figure><h1 id="c47c">Autorun and schedule task information</h1><p id="ab11">As we approached the final phase of our live forensics on the Windows machine, our attention was drawn to the C2C (Command and Control) connection, where the server was attempting to add a .bat file to the registry to establish persistence on the system. Before delving into the registry path, we conducted a preliminary check to see if any applications were located in the startup locations. Unfortunately, we did not discover any malicious applications in these areas.</p><figure id="bf7a"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*1_Ng1FqB8eP4KK8XE_jOxA.png"><figcaption></figcaption></figure><p id="43dd">At this point, our attention is directed towards the startup commands within the registry. We’ve noticed that a registry key has been added, and the associated file is named “sd.bat.”</p><div id="93c4"><pre>gwmi <span class="hljs-title class_">Win32</span>_StartupCommand</pre></div><figure id="2a07"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*6C5wTI9ysapfJD6q5WY_OA.png"><figcaption></figcaption></figure><p id="3a9e">We’ll make an effort to gather more detailed information regarding this specific startup location to gain deeper insights into the activity. This confirms that the activity recorded in network forensics has been successfully executed, and persistence has been maintained.</p><div id="f52f"><pre>gwmi Win32_StartupCommand | <span class="hljs-keyword">where</span> name -eq <span class="hljs-string">"APT"</span> | <span class="hljs-keyword">select</span> *</pre></div><figure id="8544"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*lfQO-8KyGLRyWen8Hg44-g.png"><figcaption></figcaption></figure><p id="bdef">We will now check if any other persistence activity has been observed via scheduled tasks. Unfortunately, no suspicious activity has been found.</p><div id="0fac"><pre><span class="hljs-keyword">Get</span><span class="hljs-operator">-</span>ScheduledTask <span class="hljs-operator">|</span> <span class="hljs-keyword">where</span> state <span class="hljs-operator">-</span>eq <span class="hljs-string">'Ready'</span></pre></div><figure id="cfb5"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*EihxglbQgcwtDh4rC5VPbQ.png"><figcaption></figcaption></figure><h1 id="51e5">Indicator of Attack</h1><p id="f3aa">- New user APT has been created — <b>Initial Access (T1078.003)</b>

  • User APT added to the admin group — <b>Privilege Escalation (T1098)</b>
  • The user ‘APT’ has logged into the victim’s machine using network services from the IP address 192.168.0.104 — <b>Lateral Movement (T1021.002)</b>
  • PowerShell commands were executed from a batch file, with the aim of downloading a PowerShell script and running it, providing an IP address and port number as inputs. This indicates the establishment of a reverse shell. — <b>Execution (T1059)</b>
  • I noticed a batch file added to HKU<user>\SOFTWARE\Microsoft\Windows\CurrentVersion\Run, indicating that this file will be executed upon user VictimA’s login. — <b>Persistence (T1547.001)</b></p><h1 id="afc0">Conclusion</h1><p id="3dda">The process we’ve discussed in this blog is not exhaustive, and there are other artifacts that can also be observed. We’ll aim to cover those in the next blog.</p></article></body>

Building Powerful Applications with Python Asyncio

Photo by Artturi Jalli on Unsplash

This article is part of the Python Libraries Series. Find more below!

Asynchronous programming is a paradigm that allows for more efficient and scalable applications. Asyncio, a built-in library in Python, can be used to build such applications.

Let’s discover what is asynchronous programming, how it can be used to build powerful applications, and how to use asyncio.

Asynchronous Programming

Asynchronous programming is a way of writing code that allows a program to perform multiple tasks simultaneously without blocking the execution of other code. This type of programming is particularly useful when you’re working with I/O-bound tasks, such as reading from a database, sending network requests, or waiting for user input.

In traditional synchronous programming, when a task is started, the program waits for it to complete before moving on to the next task. This can be time-consuming, especially when working with I/O-bound tasks that can take a long time to complete.

With asynchronous programming, you can start a task and then move on to another task while the first task is running. When the first task completes, it notifies the program, and the program can then process the result and move on to the next task.

As an example, let’s consider a program that needs to download data from a remote server and then process that data. In synchronous programming, the program would download the data and then wait for the download to complete before processing the data. This can take a long time, especially if the download is slow.

In asynchronous programming, the program can start the download and then move on to processing other data while the download is in progress. When the download completes, the program can process the downloaded data.

Now, let me introduce some Python asyncio concepts.

Python Asyncio Concepts

Coroutines: Coroutines are functions that can be paused and resumed. They are used to write asynchronous code. In asyncio, coroutines are defined using the async def syntax, and they are called with the await keyword.

Event Loop: The event loop is the core of asyncio. It is responsible for scheduling and running coroutines, handling I/O operations, and managing callbacks. The event loop runs in a single thread, so it is lightweight and efficient.

Futures: Futures are objects that represent the result of an asynchronous operation that hasn’t been completed yet. They can be used to wait for the completion of an asynchronous task or to run a callback function when the operation completes. In asyncio, futures are represented by the asyncio.Future class. You can create a future by calling loop.create_future().

Tasks: Tasks are a higher-level abstraction built on top of coroutines and futures. They represent the execution of a coroutine in the event loop. Tasks can be created using the asyncio.create_task() function, which schedules the coroutine to run in the event loop and returns a Task object. Tasks can be awaited just like coroutines, and they also have methods to check their status, cancel them, or add callbacks to be executed when they are completed.

Getting Started with Asyncio

Let’s start with a basic example to understand the asyncio syntax. First, we need to import asyncio:

import asyncio

Then, let’s define a coroutine function using the async def syntax:

async def my_coroutine():
print("Starting coroutine")
await asyncio.sleep(1)
print("Coroutine finished")

Now, we can create an event loop. The event loop is responsible for managing the execution of coroutines and other asynchronous operations.

loop = asyncio.get_event_loop()

We can now schedule the coroutine to run on the event loop using the asyncio.create_task() method. This method creates a Task object that represents the execution of the coroutine.

task = asyncio.create_task(my_coroutine())

To run the event loop, we can use loop.run_until_complete(task). And finally, we can close the event loop using loop.close()

A more complex example

The example above was just here to make you understand the asyncio syntax. Now let’s move on to a more complex example. The idea of the example is to retrieve data from different data sources and process them, asynchronously obviously. Let’s start by importing the libraries we’ll need.

import asyncio
import random

We define now a coroutine function called fetch_data() that takes a URL as an argument. This coroutine simulates fetching data from a URL by sleeping for a random amount of time between 1 and 3 seconds using the asyncio.sleep() function. We print a message before and after the sleep to show when the coroutine starts and finishes.

async def fetch_data(url):
  print(f"Fetching data from {url}")
  await asyncio.sleep(random.randint(1, 3)) # Simulate a network delay
  print(f"Received data from {url}")
  return f"Data from {url}"

Then we define another coroutine function called process_data() that takes data as an argument. This coroutine simulates processing the data, also by sleeping for a random amount of time between 1 and 3 seconds.

async def process_data(data):
  print(f"Processing data {data}")
  await asyncio.sleep(random.randint(1, 3)) # Simulate a CPU-bound task
  print(f"Processed data {data}")
  return f"Processed data {data}"

Now, we define the main() coroutine function that creates a list of URLs to fetch data from, creates a task for each URL using the asyncio.create_task() function, and runs the tasks concurrently using the asyncio.gather() function. We print the results of the asyncio.gather() function to show the processed data.

async def main():
  urls = ["https://example.com", "https://google.com", "https://github.com"]
  tasks = [asyncio.create_task(fetch_data(url)) for url in urls]
  fetched_data = await asyncio.gather(*tasks)
  processed_data = await asyncio.gather(*(process_data(data) for data in fetched_data))
  print(processed_data)

The last step is to run our program using asyncio.run(main())

The output should look like the following:

Fetching data from https://example.com
Fetching data from https://google.com
Fetching data from https://github.com
Received data from https://example.com
Received data from https://google.com
Received data from https://github.com
Processing data Data from https://example.com
Processing data Data from https://google.com
Processing data Data from https://github.com
Processed data Processed data Data from https://example.com
Processed data Processed data Data from https://google.com
Processed data Processed data Data from https://github.com
['Processed data Data from https://example.com', 'Processed data Data from https://google.com', 'Processed data Data from https://github.com']

Debugging Asynchronous Code

Debugging asynchronous code in Python can be a bit tricky due to the nature of the event loop and the way the code is executed. That’s why there are some guidelines to follow when you want to debug this type of code.

Using the asyncio debugger: The asyncio module provides a built-in debugger that can be used to debug your asynchronous code. You can enable the debugger by adding the following lines to your code:

import asyncio
asyncio.get_event_loop().set_debug(True)

This will enable debug output from the event loop, which can help you identify issues with your code.

Using print statements (or any third-party logging librairies): Sometimes the easiest way to debug your code is to add print statements to your code. Since asyncio code is executed asynchronously, adding print statements can help you understand the order in which your code is executed and identify any issues.

import asyncio

async def my_coroutine():
  print("Starting my_coroutine")
  await asyncio.sleep(1)
  print("Finished my_coroutine")

async def main():
  print("Starting main")
  await my_coroutine()
  print("Finished main")

asyncio.run(main())

Using a third-party debugger: Another option is to use a third-party debugger that is designed specifically for asyncio code. Two popular options are aiohttp-devtools and asyncio_debugger.

import aiohttp_devtools
aiohttp_devtools.setup()
import asyncio_debugger
asyncio_debugger.init()

Use breakpoints: If you are using an IDE like PyCharm or VSCode, you can set breakpoints in your asyncio code and use the debugger to step through your code.

import asyncio

async def my_coroutine():
  breakpoint()
  await asyncio.sleep(1)
  print("Finished my_coroutine")

async def main():
  breakpoint()
  await my_coroutine()
  print("Finished main")

asyncio.run(main())

Asyncio best practices

First, it’s important to design your application with concurrency in mind from the start, breaking it down into small, self-contained tasks that can be run concurrently. This requires careful planning of the flow of data and communication between tasks, as well as an understanding of the event loop and how it manages tasks.

Then, you should avoid blocking operations within your asynchronous code. This means avoiding I/O operations that might block the event loop, and instead using asyncio-compatible libraries or asynchronous APIs wherever possible. If you need to use a synchronous library or function, consider wrapping it in a separate thread or process to avoid blocking the event loop, else there’s no purpose in writing asynchronous code.

Thirdly, pay close attention to error handling and propagation. Exceptions raised in asynchronous code can be tricky to handle correctly, especially when dealing with multiple concurrent tasks. You should use asyncio’s built-in exception handling mechanisms to catch and propagate exceptions between tasks and coroutines, and to ensure that any errors are properly logged or reported to the user.

Lastly, it’s important to test your code thoroughly, including edge cases and error conditions. Asynchronous code can be more complex to test than synchronous code, and you should make use of asyncio-specific testing frameworks and tools to ensure that your code is working correctly.

Use Cases

Asynchronous code can be used to build powerful applications as it allows your program to run several tasks at the same time, but what could this be useful for?

Web scraping: Python asyncio can be used for web scraping as it allows the scraping of multiple websites simultaneously. This can be achieved by using the aiohttp library, which is an asynchronous HTTP client/server library.

Network programming: asyncio can be used for building high-performance networking applications. It provides a way to handle thousands of simultaneous connections in a single thread, which is useful for building real-time chat applications, multiplayer games, and more.

Distributed computing: asyncio provides a way to write distributed systems as it uses asynchronous code. This can be useful for building distributed data processing systems or building distributed web applications.

Asynchronous task scheduling: Python asyncio can be used for running background tasks, such as sending emails, processing files, etc…

Web development: the asyncio library provides support for asynchronous web frameworks such as aiohttp, which can be used to build web applications.

Final Note

Asynchronous programming can be very powerful depending on the application you want to build.

I hope to have provided you with a good knowledge base to start with asynchronous programming with asyncio!

If you want to discover other Python libraries, click below!

If you liked the story, don’t forget to clap and maybe follow me if you want to explore more of my content :)

You can also subscribe to me via email to be notified every time I publish a new story, just click here!

If you’re not subscribed to medium yet and wish to support me or get access to all my stories, you can use my link:

Python
Programming
Coding
Software Development
Technology
Recommended from ReadMedium