CGI 是 Web 服务器运行时外部程序的规范,按照 CGI 编写的程序可扩展服务器功能。CGI 程序运行在 HTTP 服务器中,为 HTTP 服务器与其他第三方应用程序之间提供数据交换手段。程序的大部分采用 C 语言编写,通过系统函数调用来控制设备,以此达到灵活高效又能控制设备的目的。
如上图所示,Web 服务器发送 HTTP 请求 Request 到 CGI 进程,CGI 进程把 HTTP 请求的 Header 设置为进程的环境变量。
pass.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* getcgidata(FILE* fp, char* requestmethod);
int main() {
char* input;
char* req_method;
char name[64];
char pass[64];
int i = 0;
int j = 0;
// printf("Content-type: text/plain; charset=iso-8859-1\n\n");
printf("Content-type: text/html\n\n");
printf("The following is query reuslt:<br><br>");
req_method = getenv("REQUEST_METHOD");
input = getcgidata(stdin, req_method);
// 我们获取的input字符串可能像如下的形式
// Username="admin"&Password="aaaaa"
// 其中"Username="和"&Password="都是固定的
// 而"admin"和"aaaaa"都是变化的,也是我们要获取的
// 前面9个字符是UserName=
// 在"UserName="和"&"之间的是我们要取出来的用户名
for (i = 9; i < (int)strlen(input); i++) {
if (input[i] == '&') {
name[j] = '\0';
break;
}
name[j++] = input[i];
}
// 前面9个字符 + "&Password="10个字符 + Username的字符数
// 是我们不要的,故省略掉,不拷贝
for (i = 19 + strlen(name), j = 0; i < (int)strlen(input); i++) {
pass[j++] = input[i];
}
pass[j] = '\0';
printf("Your Username is %s<br>Your Password is %s<br> \n", name, pass);
return 0;
}
char* getcgidata(FILE* fp, char* requestmethod) {
char* input;
int len;
int size = 1024;
int i = 0;
if (!strcmp(requestmethod, "GET")) {
input = getenv("QUERY_STRING");
return input;
} else if (!strcmp(requestmethod, "POST")) {
len = atoi(getenv("CONTENT_LENGTH"));
input = (char*)malloc(sizeof(char) * (size + 1));
if (len == 0) {
input[0] = '\0';
return input;
}
while (1) {
input[i] = (char)fgetc(fp);
if (i == size) {
input[i + 1] = '\0';
return input;
}
--len;
if (feof(fp) || (!(len))) {
i++;
input[i] = '\0';
return input;
}
i++;
}
}
return NULL;
}
HTTP 请求的 Body 正文设置为进程的标准输入,CGI 进程的标准输出作为 HTTP 数据包响应 Web 服务器的请求。
test.c
#include <stdio.h>
int main()
{
printf("Content-type:text/html\n\n"); //这句一定要加上
printf("<html><body>");
printf("<font style=\"color:red; font-size:30px;\">Hello, CGI!</font><br/>");
printf("<a href=\"/index.html\">return index.html</a>");
printf("</body></html>");
return 0;
}
环境变量是指 CGI 程序定义的一组环境变量,通过环境变量可以传递数据。常用 CGI 程序环境变量如下表所示:
CGI 程序通过函数 environ 可以获取所有的环境变量及其值,通过函数 getenv 可以获得指定环境变量的对应值。
QUERY_STRING:获取 CGI 程序 URL 中 '?' 之后的数据。
REQUEST_METHOD:判断 CGI 请求所采用的请求方法,以决定是通过 stdin 还是通过环境变量 QUERY_STRING 获取客户端传输数据。
通过如下命令,可以将 c 文件,生成 cgi 程序:
gcc -static -o test.cgi test.c
[1]常天佑,朱涛,宋健,等.面向嵌入式CGI的命令注入漏洞挖掘研究[J].计算机时代,2023,(04):1-4+10.DOI:10.16644/j.cnki.cn33-1094/tp.2023.04.001.