为了了解PHP、JSP、ASP出现之前人们写网站的方法,洒家研究了一波CGI,使用C、Python、batch、shell script语言写了几个简单的网页。

CGI即通用网关接口,指web服务器调用编程语言编写的程序的一个接口。洒家用的是Apache的CGI,QUERY_STRING、REMOTE_ADDR、REQUEST_URI等参数是通过环境变量传递给CGI程序的,请求主体(POST数据)作为CGI程序的标准输入(stdin),而CGI程序的标准输出(stdout)作为HTTP响应的部分(注:标准错误输出stderr会出现在错误日志中)。

系统和软件环境配置

WAMP Apache 2.4.18 64位, Ubuntu Server 16.04 64位。

需要开启Apache的cgi_module。

sudo a2enmod cgi
sudo service apache2 restart

对于Linux,cgi-bin的目录在 /etc/apache2/conf-enabled/serve-cgi-bin.conf 中规定,使用浏览器访问这个目录的alias:/cgi-bin/。对于Windows 下的WAMP套件,对应目录默认在安装目录内(例如C:/wamp64/cgi-bin/)。

由于洒家对Linux不熟悉,踩到了几个坑

1. 对于Ubuntu中 shell script,开头的#!/bin/sh 和 #!/bin/bash 是不同的。Ubuntu 的 /bin/sh 是 /bin/dash (Debian Almquist shell)的链接。对于 echo -e 'Content-Type: abc\n'的执行结果不同。

2. HTTP响应头和响应主体之间要有一个换行符,否则无法分清响应主体和响应头部。

3. Linux上的程序要加可执行文件权限。否则报500错误 Permission denied: exec of '/usr/lib/cgi-bin/env_var.sh' failed: /usr/lib/cgi-bin/env_var.sh 。

4. shell script 执行字符串要用eval,否则不能把引号中带空格的字符串识别为同一个参数。

参考

通用网关接口-维基百科

C语言CGI编程入门(一)

鸟哥的Linux私房菜-Shell的变量功能

用C、Python、Shell Script、batch(批处理)写的几个小程序

编程语言Perl是一个广泛被用来编写CGI程序的语言,但CGI的一个目的是要独立于任何语言的。Web服务器无须在这个问题上对语言有任何了解。事实上,CGI程序可以用任何脚本语言或者是完全独立编程语言实现,只要这个语言可以在这个系统上运行。除Perl外,像Unix shell script, Python, Ruby, PHP, Tcl, C/C++,和Visual Basic都可以用来编写CGI程序。

洒家看到这段话的时候想,哇塞,还可以用C语言写网站!洒家顿时感到了历史的气息。

查看所有的环境变量

在Linux下可以用 env 命令,列出所有的环境变量。注意,HTTP响应头和响应主体之间要有一个换行符,否则无法分清响应主体和响应头部,报错: malformed header from script 'env_var.sh': Bad header: SERVER_SIGNATURE=<address>Apac 。

使用 shell script脚本:

#!/bin/bash
echo -e "Content-Type: text/html\n"
env

响应:

HTTP/1.1 200 OK
Date: Sun, 23 Oct 2016 13:10:01 GMT
Server: Apache/2.4.18 (Ubuntu)
X-Author: http://www.cnblogs.com/go2bed/
Vary: Accept-Encoding
Content-Length: 1180
Connection: close
Content-Type: text/html SERVER_SIGNATURE=<address>Apache/2.4.18 (Ubuntu) Server at 192.168.245.136 Port 80</address> HTTP_USER_AGENT=Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_1) AppleWebKit/601.2.7 (KHTML, like Gecko) Version/9.0.1 Safari/601.2.7
SERVER_PORT=80
HTTP_HOST=192.168.245.136
(省略)

Hello World

Linux/Windows,C语言,请求的时候要请求编译好的二进制程序。

#include <stdio.h>

int main()
{
printf("Content-Type: text/html\n\n");
printf("Hello World!\n");
return ;
}

效果:

一个 say hello 的动态网页

Linux/Windows,Python ,头部需要加Python可执行文件的位置。对于Windows,则可能是 #!C:/Python27/python.exe 。

#!/usr/local/bin/python
import os
import urllib
import sys
import cgi
print 'Content-Type: text/html\n' postData = sys.stdin.read()
if postData != '':
items = postData.split('&')
for item in items:
key,value = urllib.splitvalue(item)
if key == 'name':
print '<h1>Hello, %s</h1>' % (cgi.escape(urllib.unquote_plus(value)),)
print '''<form action="" method="POST">
<input name="name" type="text" placeholder="Your name" />
<input type="submit" />
</form>'''
print os.environ['QUERY_STRING']

效果如下图。此程序读取POST数据(stdin),Tom未在URL中出现。

另一个say hello 的动态网页

Windows/Linux,C语言。此处没有做URL decode。

#include <stdio.h>
#include <stdlib.h>
#include <string.h> int main()
{
int i;
char * query;
query = getenv("QUERY_STRING");
printf("Content-type:text/html\n\n");
if(getenv("QUERY_STRING") != NULL && strlen(getenv("QUERY_STRING")) > )
{
printf("<h1>Hello %s</h1><br />\n", query + );
}
printf("<form action=\"\" method=\"GET\"><input type=\"text\" name=\"name\" autofocus/><input type=\"submit\"/></form>"); return ;
}

执行任意命令的Webshell,及其过程与经验

Linux,shell script

#!/bin/bash

echo -e 'Content-Type: text/html\n'

echo '<h1>I am using cgi (shell script)</h1>'
echo '<form action="" method="GET">'
echo '<input type="text" name="cmd" autofocus />'
echo '<input type="submit" />'
echo '</form>' echo -e '\n<pre>\n'
#echo ${QUERY_STRING}
cmd=${QUERY_STRING#'cmd='}
#echo ${cmd}
cmd=${cmd:-'ping -c 2 baidu.com'}
cmd=$(echo ${cmd}| python -c 'import sys;import urllib;sys.stdout.write(urllib.unquote_plus(sys.stdin.read()))')
echo ${cmd}
echo '<hr />'
eval ${cmd} >&

#ping -c baidu.com
echo -e '\n</pre>\n'

效果:

由于洒家对shell这门精妙的语言不甚了解,以为在shell script中执行一个命令(字符串)直接写上即可,一开始上文加粗的字体写的命令是 ${cmd} >& 。这一个脚本在命令执行的时候有一些奇怪的地方。例如执行  python -c 'import this' 时,会报错:

  File "", line 1
'import
^
SyntaxError: EOL while scanning string literal

这个错误输出和下面的情况的输出相同:

user@localhost:/usr/lib/cgi-bin$ cmd=python\ -c\ \'import\ this\'
user@localhost:/usr/lib/cgi-bin$ echo $cmd
python -c 'import this'
user@localhost:/usr/lib/cgi-bin$ $cmd
File "<string>", line 1
'import
^
SyntaxError: EOL while scanning string literal

user@localhost:/usr/lib/cgi-bin$ eval $cmd
The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.

经过一番研究之后洒家恍然大悟,这个报错表示,Python收到的参数(sys.argv[2])为  'import ,单引号的作用不是命令行中参数的边界,而是直接作为参数的一部分传进了Python。也就是说,直接执行  ${cmd} 相当于Python中的

subprocess.call(["python","-c","'import","this'"])

一个字符串变量直接执行会有问题,正确的做法要用eval命令“扫描两次”,才能正确解析。使用 eval ${cmd} 使shell重新扫描命令,把 import 和 this看做同一个参数,相当于 subprocess.call(["python","-c","import this"]) 。

总而言之,这次的错误类似于这种情况:

user@localhost:/usr/lib/cgi-bin$ pipe="|"
user@localhost:/usr/lib/cgi-bin$ ls $pipe grep sh
ls: cannot access '|': No such file or directory
ls: cannot access 'grep': No such file or directory
ls: cannot access 'sh': No such file or directory
user@localhost:/usr/lib/cgi-bin$ eval ls $pipe grep sh
env_var.sh
test.sh

使用Windows batch script(批处理)写的一个功能有限的webshell

批处理,这个的坑也有点多,而且洒家也不太熟悉,只能写这么多了。

@echo off
echo Content-Type: text/html; charset=GBK
echo. echo ^<h1^>batch webshell^</h1^>
echo ^<form action="" method="GET"^>
echo ^<input type="text" name="cmd" autofocus /^>
echo ^<input type="submit" /^>
echo ^</form^> echo ^<pre^>
set ccmmdd=%QUERY_STRING:~4%
set ccmmdd=%ccmmdd:+= %
set ccmmdd=%ccmmdd:^%20= %
echo ^<textarea style="width:100%%;height:60%%;"^>
%ccmmdd%
echo ^</textarea^>
echo ^</pre^>

几种语言的CGI编程的更多相关文章

  1. (笔记)Linux下的简单CGI编程

    为什么要进行CGI编程?  在HTML中,当客户填写了表单,并按下了发送(submit)按钮后,表单的内容被发送到了服务器端,一般的,这时就需要有一个服务器端脚本来对表单的内容进行一些处理,或者是把它 ...

  2. C语言写CGI程序

    一.CGI概述 CGI(公用网关接口)规定了Web服务器调用其他可执行程序(CGI程序)的接口协议标准.Web服务器通过调用CGI程序实现和Web浏览器的交互, 也就是CGI程序接受Web浏览器发送给 ...

  3. Linux CGI编程基础【整理】

    Linux CGI编程基础 1.为什么使用CGI? 如前面所见,任何的HTML均是静态网页,它无法实现一些复杂的功能,而CGI可以为我们实现.如:a.列出服务器上某个目录中的文件,对目录中的文件进行操 ...

  4. 5种语言混合编程:C++、JS、python、Lisp、汇编

    /* 混合C++.JS.python.Lisp.汇编 1种语言,5种语法 */ main { //C++ vector<int> v; v.push(2); putsl(v.size()) ...

  5. CGI编程

    1简介 .CGI:通用网关接口(Common Gateway Interface)是一个Web服务器主机提供信息服务的标准接口,服务器和客户端之间的通信,是客户端的浏览器和服务器端的http服务器之间 ...

  6. CGI编程学习

    @CGI编程学习 目录(?)[+] 一.基本原理 CGI:通用网关接口(Common Gateway Interface)是一个Web服务器主机提供信息服务的标准接口.通过CGI接口,Web服务器就能 ...

  7. 雷林鹏分享:Ruby CGI 编程

    Ruby CGI 编程 Ruby 是一门通用的语言,不仅仅是一门应用于WEB开发的语言,但 Ruby 在WEB应用及WEB工具中的开发是最常见的. 使用Ruby您不仅可以编写自己的SMTP服务器,FT ...

  8. Python3 CGI编程实现教程

    一.背景说明 虽然很久以前就听说“早期的网站很多通过cgi形式实现”.“C++可通过CGI形式编写网页”,日积月累对CGI也有了一些概念,但一直没真正见过一个实际运行的CGI网站,总归还是有些底气不足 ...

  9. python CGI 编程实践

    文章更新于:2020-03-05 注1:安装 python 参见: python 的安装使用和基本语法 注2:配置 web 环境参见: Windows&linux使用集成环境搭建 web 服务 ...

随机推荐

  1. Web Serveice服务代理类生成及编译

    本文链接地址:http://www.cnblogs.com/dengxinglin/p/3334158.html 一.生成代理类 对于web service服务和wcf的webservice服务,我们 ...

  2. Molecule – 帮助你构建跨平台的 HTML5 游戏

    Molecule 框架由拥有超过五年手机游戏开发经验的游戏开发者开发.由于移动浏览器与实际的 HTML5 规范的兼容性的改进和内部硬件的自然进化,HTML5 手机游戏真正有可能流行起来. 您可能感兴趣 ...

  3. windows 端口 任务

  4. javascript --- 设计模式之创造者模式

    在软件系统中,有时候面临着“一个复杂对象”的创建工作,其通常由各个部分的子对象用一定的算法构成:由于需求的变化,这个复杂对象的各个部分经常面临着剧烈的变化,但是将它们组合在一起的算法确相对稳定.如何应 ...

  5. CRM 2013 中业务流程的

    在CRM 2013 中有一个新功能就业务流程,它可以引导用户在既定好的业务规则下操作表单,实现业务之前的衔接.并且让衔接可以视化,能清楚定位到当前的流程在那个节点.我们在配置视图的时候可以将流程阶段放 ...

  6. SharePoint 2013 搜索报错"Unable to retrieve topology component health. This may be because the admin component is not up and running"

    环境描述 Windows 2012 R2,SharePoint 2013(没有sp1补丁),sql server 2012 错误描述 搜索服务正常,但是爬网一直在Crawling Full,但是爬不到 ...

  7. tomcat通过socket连接MySQL,不再占用服务端口【linux】

    MySQL连接方式的说明 http://icbm.iteye.com/blog/1840673 MySQL除了最常见的TCP连接方式外,还提供SOCKET(LINUX默认连接方式).PIPE和SHAR ...

  8. git 删除远程源,新增加源

    git remote remove origin git remote add origin git@XXXX

  9. Ubuntu 16.04 LTS 安装配置 Nginx 1.10.0 Php7.0-FPM

    1. 安装Nginx,Php-7.0 ~$ sudo add-apt-repository ppa:nginx/stable ~$ sudo apt-get update ~$ sudo apt-ge ...

  10. Gradle常用命令

    使用cmd进入Android studio项目的根目录就可以执行一些gradle相关命令 gradle -v 查看版本 (如果你是第一次执行会去下载Gradle,这个过程如果不FQ非常慢) gradl ...