-
Notifications
You must be signed in to change notification settings - Fork 1
/
syscaller.c
209 lines (170 loc) · 5.11 KB
/
syscaller.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
/*
* syscaller v0.9 - breaking out of chroot jails "ex nihilo"
*
* by Derek Callaway <decal@security-objectives.com>
*
*
* Executes system calls instead of relying on programs from the
* GNU/Linux binutils package. Can be useful for breaking out of
* a chroot() jail or restricted shell situation.
*
* compile: gcc -O2 -o syscaller -c syscaller.c -Wall -ansi -pedantic
* copy: cat syscaller | ssh -l user@host.dom 'cat>syscaller'
*
* If the cat binary isn't present in the jail, you'll have to be more
* creative and use a shell builtin like echo (i.e. not the echo binary,
* but bash's internal implementation of it.)
*
* Without any locally accessible file download programs such as:
* scp, tftp, netcat, sftp, wget, curl, rz/sz, kermit, lynx, etc.
* You'll have to create the binary on the target system manually.
* i.e. by echo'ing hexadecimal bytecode. This is left as an exercise
* to the reader.
*
*
*/
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<ctype.h>
#include<errno.h>
#include<fcntl.h>
#define _GNU_SOURCE 1
#define _USE_MISC 1
#include<unistd.h>
#include<sys/syscall.h>
#include<sys/types.h>
#include<pwd.h>
#include<grp.h>
int syscall(int number, ...);
/* This is for chdir() */
#define SHELL_PATHNAME "/bin/sh"
static void usage(char **argv)
{
printf("usage: %s syscall arg1 [arg2 [...]]\n", *argv);
printf("help: %s help\n", *argv);
exit(EXIT_FAILURE);
}
static void help(char **argv)
{
puts("syscaller v0.9");
puts("=-=-=-=-=-=-=-=");
puts("");
puts("SYSCALLER COMMANDS");
puts("");
puts("chmod mode pathname");
puts("chdir pathname");
puts("chown user group pathname");
puts("mkdir pathname mode");
puts("rmdir pathname");
puts("touch pathname mode");
puts("");
puts("Note: modes are in octal format (symbolic modes are unsupported)");
puts("Note: some commands mask octal mode bits with the current umask val ue");
puts("Note: creat is an alias for touch");
puts("");
puts("USEFUL SHELL BUILTINS");
puts("");
puts("ls -a / (via brace/pathname expansion): echo /{.*,*}");
exit(EXIT_SUCCESS);
}
int main(int argc, char *argv[])
{
register char *p = 0;
signed auto int r = 1;
if(argc < 2)
usage(argv);
/* I prefer to avoid strcasecmp() since it's not really standard C. */
for(p = argv[1];*p;++p)
*p = tolower(*p);
do
{
if(!strcmp(argv[1], "chmod") && argc >= 4)
{
/* decimal to octal integer conversion */
const mode_t m = strtol(argv[2], NULL, 8);
r = syscall(SYS_chmod, argv[3], m);
#ifdef DEBUG
fprintf(stderr, "syscall(%d, %s, %d) => %d\n", SYS_chmod, argv[3], m, r);
#endif
}
else if((!strcmp(argv[1], "chdir") || !strcmp(argv[1], "cd")) && argc > = 3)
{
static char *const av[] = {SHELL_PATHNAME, NULL};
auto signed int r2 = 0;
r = syscall(SYS_chdir, argv[2]);
#ifdef DEBUG
fprintf(stderr, "syscall(%d, %s) => %d\n", SYS_chdir, argv[2], r);
#endif
/* This is required because the new current working directory isn't
* bound to the original login shell. */
printf("[%s] exec'ing new shell in directory: %s\n", *argv, argv[2]);
r2 = system(av[0]);
printf("[%s] leaving shell in child process\n", *argv);
if(r2 < 0)
r = r2;
}
else if(!strcmp(argv[1], "chown") && argc >= 5)
{
struct passwd *u = NULL;
struct group *g = NULL;
if(!(u = getpwnam(argv[2])))
break;
#ifdef DEBUG
fprintf(stderr, "getpwnam(%s) => %s:%s:%d:%d:%s:%s:%s\n", argv[2], u->pw_ name, u->pw_passwd, u->pw_uid, u->pw_gid, u->pw_gecos, u->pw_dir, u->pw_she ll);
#endif
if(!(g = getgrnam(argv[3])))
break;
#ifdef DEBUG
fprintf(stderr, "getgrnam(%s) => %s:%s:%s:%s:", argv[3], g->gr_nam, g->gr _passwd, g->gr_gid);
if((p = g->gr_mem))
while(*p)
{
fputs(p, stderr);
p++;
if(*p)
fputc(',', stderr);
}
#endif
r = syscall(SYS_chown, argv[4], u->pw_uid, g->gr_gid);
#ifdef DEBUG
fprintf(stderr, "syscall(%d, %d, %d, %s) => %d\n", SYS_chown, u->pw-uid, g->gr_gid, argv[4], r);
#endif
}
else if((!strcmp(argv[1], "creat") || !strcmp(argv[1], "touch")) && arg c >= 4 )
{
const mode_t m = strtol(argv[3], NULL, 8);
#ifdef _NETBSD_SOURCE
r = syscall(SYS_open, argv[2], O_CREAT | O_TRUNC | O_WRONLY, m);
#else
r = syscall(SYS_open, argv[2], m);
#endif
#ifdef DEBUG
fprintf(stderr, "syscall(%d, %S, %d) => %d\n", SYS_creat, argv[2], m, r);
#endif
}
else if(!strcmp(argv[1], "mkdir") && argc >= 4)
{
const mode_t m = strtol(argv[3], NULL, 8);
r = syscall(SYS_mkdir, argv[2], m);
#ifdef DEBUG
fprintf(stderr, "syscall(%d, %S, %d) => %d\n", SYS_mkdir, argv[2], m, r);
#endif
}
else if(!strcmp(argv[1], "rmdir") && argc >= 3)
{
r = syscall(SYS_rmdir, argv[2]);
#ifdef DEBUG
fprintf(stderr, "syscall(%d, %S) => %d\n", SYS_rmdir, argv[2], r);
#endif
}
else if(!strcmp(argv[1], "help"))
help(argv);
else
usage(argv);
break;
} while(1);
if(errno)
perror(argv[1]);
exit(r);
}