草庐IT

Hadoop运维记录系列(二十一)

Slaytanic 2023-03-28 原文
Zeppelin启用https过程和Hack内核以满足客户需求的记录。

原因是这客户很有意思,该客户中国分公司的人为了验证内网安全性,从国外找了一个渗透测试小组对Zeppelin和其他产品进行黑客测试,结果发现Zeppelin主要俩问题,一个是在内网没用https,一个是zeppelin里面可以执行shell命令和python语句。其实这不算大问题,zeppelin本来就是干这个用的。但是渗透小组不了解zeppelin是做什么的,认为即使在内网里,执行shell命令能查看操作系统的一些文件是大问题,然后发生的事就不说了,不是我们的问题了。


不过既然他们要求整改,我们也只好配合,虽然大家都觉得内网域名加https属于脱了裤子放屁,然后不让zeppelin干他本来应该干的事就更过分了,但鉴于客户是甲方,也只好hack源码了。


于是某个周末用了4个小时完成所有工作。


先记录下zeppelin加https访问,我们有自己的域名证书,所以直接用即可。如果没有域名证书,需要自签发,那么可以看第二部分,双向认证步骤。

https第一部分,已有域名添加jks:

openssl pkcs12 -export -in xxx.com.crt -inkey xxx.com.key -out xxx.com.pkcs12 keytool -importkeystore -srckeystore xxx.com.pkcs12 -destkeystore xxx.com.jks -srcstoretype pkcs12https第二部分,自签发证书双向认证添加jks

# 生成root私钥和证书文件。 openssl genrsa -out root.key(pem) 2048 # Generate root key file openssl req -x509 -new -key root.key(pem) -out root.crt # Generate root cert file # 创建客户端私钥和证书以及证书请求文件csr openssl genrsa -out client.key(pem) 2048 # Generate client key file openssl req -new -key client.key(pem) -out client.csr # Generate client cert request file openssl x509 -req -in client.csr -CA root.crt -CAkey root.key(pem) -CAcreateserial -days 3650 -out client.crt # Use root cert to generate client cert file # 生成服务器端私钥,证书和证书请求文件csr openssl genrsa -out server.key(pem) 2048 # Generate server key file, use in Zeppelin openssl req -new -key server.key(pem) out server.csr @ Generate server cert request file openssl x509 -req -in server.csr -CA root.crt -CAkey root.key(pem) -CAcreateserial -days 3650 -out server.crt # Use root cert to generate server cert file # 生成客户端端jks文件 openssl pkcs12 -export -in client.crt -inkey client.key(pem) -out client.pkcs12 # Package to pkcs12 format, must input a password, you should remember the password keytool -importkeystore -srckeystore client.pkcs12 -destkeystore client.jks -srcstoretype pkcs12 # The client password you just input at last step # 生成服务器端jks文件 openssl pkcs12 -export -in server.crt -inkey server.key(pem) -out server.pkcs12 @ Package to pkcs12 format, must input a password, you should remember the password keytool -importkeystore -srckeystore server.pkcs12 -destkeystore server.jks -srcstoretype pkcs12 # The server password you just input at last step如果是不需要双向认证,只要单向自签发,不创建客户端的各种就可以了。

然后找个地把这些文件放过去,再修改zeppelin配置即可。

mkdir -p /etc/zeppelin/conf/ssl cp server.crt server.jks /etc/zeppelin/conf/ssl<property>   <name>zeppelin.server.ssl.port</name>   <value>8443</value>   <description>Server ssl port. (used when ssl property is set to true)</description> </property> <property>   <name>zeppelin.ssl</name>   <value>true</value>   <description>Should SSL be used by the servers?</description> </property> <property>   <name>zeppelin.ssl.client.auth</name>   <value>false</value>   <description>Should client authentication be used for SSL connections?</description> </property> <property>   <name>zeppelin.ssl.keystore.path</name>   <value>/etc/zeppelin/conf/ssl/xxx.com.jks</value>   <description>Path to keystore relative to Zeppelin configuration directory</description> </property> <property>   <name>zeppelin.ssl.keystore.type</name>   <value>JKS</value>   <description>The format of the given keystore (e.g. JKS or PKCS12)</description> </property> <property>   <name>zeppelin.ssl.keystore.password</name>   <value>password which you input on generating server jks step</value>   <description>Keystore password. Can be obfuscated by the Jetty Password tool</description> </property>

然后反代那里也加上443的ssl证书以及443转8443的upstream即可。


然后是hack zeppelin源码加入关键字限制,这个确实找了一小会zeppelin发送执行源码给interpreter的地方,zeppelin架构比较清晰,但是代码挺复杂的,用到了很多小花活儿。比如thrift,interpreter脚本里建立nc监听。然后各个解释器插件用socket跟interpreter脚本通信,前端angular,后端jetty,还用shiro做验证和授权。回头可以单开好几篇说说zeppelin安装,使用和详细配置,做这项目基本把zeppelin摸透了。

找到发送前端编写内容给interpreter的java代码,然后用很生硬的办法限制执行命令。具体那个.java文件的名字我就不说了,有悬念有惊喜。我不写java,只负责读源码找到代码位置,hack的java是同事写的。然后编译,替换jar包,完成。后面改了改配置,后续的渗透测试顺利通过。

static HashSet<String[]> blockedCodeString = new HashSet<>();   static {     blockedCodeString.add(new String[]{"import", "os"});     blockedCodeString.add(new String[]{"import", "sys"});     blockedCodeString.add(new String[]{"import", "subprocess"});     blockedCodeString.add(new String[]{"import", "pty"});     blockedCodeString.add(new String[]{"import", "socket"});     blockedCodeString.add(new String[]{"import", "commands"});     blockedCodeString.add(new String[]{"import", "paramiko"});     blockedCodeString.add(new String[]{"import", "pexpect"});     blockedCodeString.add(new String[]{"import", "BaseHTTPServer"});     blockedCodeString.add(new String[]{"import", "ConfigParser"});     blockedCodeString.add(new String[]{"import", "platform"});     blockedCodeString.add(new String[]{"import", "popen2"});     blockedCodeString.add(new String[]{"import", "copy"});     blockedCodeString.add(new String[]{"import", "SocketServer"});     blockedCodeString.add(new String[]{"import", "sysconfig"});     blockedCodeString.add(new String[]{"import", "tty"});     blockedCodeString.add(new String[]{"import", "xmlrpmlib"});     blockedCodeString.add(new String[]{"etc"});     blockedCodeString.add(new String[]{"boot"});     blockedCodeString.add(new String[]{"dev"});     blockedCodeString.add(new String[]{"lib"});     blockedCodeString.add(new String[]{"lib64"});     blockedCodeString.add(new String[]{"lost+found"});     blockedCodeString.add(new String[]{"mnt"});     blockedCodeString.add(new String[]{"proc"});     blockedCodeString.add(new String[]{"root"});     blockedCodeString.add(new String[]{"sbin"});     blockedCodeString.add(new String[]{"selinux"});     blockedCodeString.add(new String[]{"usr"});     blockedCodeString.add(new String[]{"passwd"});     blockedCodeString.add(new String[]{"useradd"});     blockedCodeString.add(new String[]{"userdel"});     blockedCodeString.add(new String[]{"rm"});     blockedCodeString.add(new String[]{"akka "});     blockedCodeString.add(new String[]{"groupadd"});     blockedCodeString.add(new String[]{"groupdel"});     blockedCodeString.add(new String[]{"mkdir"});     blockedCodeString.add(new String[]{"rmdir"});     blockedCodeString.add(new String[]{"ping"});     blockedCodeString.add(new String[]{"nc"});     blockedCodeString.add(new String[]{"telnet"});     blockedCodeString.add(new String[]{"ftp"});     blockedCodeString.add(new String[]{"scp"});     blockedCodeString.add(new String[]{"ssh"});     blockedCodeString.add(new String[]{"ps"});     blockedCodeString.add(new String[]{"hostname"});     blockedCodeString.add(new String[]{"uname"});     blockedCodeString.add(new String[]{"vim"});     blockedCodeString.add(new String[]{"nano"});     blockedCodeString.add(new String[]{"top"});     blockedCodeString.add(new String[]{"cat"});     blockedCodeString.add(new String[]{"more"});     blockedCodeString.add(new String[]{"less"});     blockedCodeString.add(new String[]{"chkconfig"});     blockedCodeString.add(new String[]{"service"});     blockedCodeString.add(new String[]{"netstat"});     blockedCodeString.add(new String[]{"iptables"});     blockedCodeString.add(new String[]{"ip"});     blockedCodeString.add(new String[]{"route "});     blockedCodeString.add(new String[]{"curl"});     blockedCodeString.add(new String[]{"wget"});     blockedCodeString.add(new String[]{"sysctl"});     blockedCodeString.add(new String[]{"touch"});     blockedCodeString.add(new String[]{"scala.sys.process"});     blockedCodeString.add(new String[]{"0.0.0.0"});     blockedCodeString.add(new String[]{"git"});     blockedCodeString.add(new String[]{"svn"});     blockedCodeString.add(new String[]{"hg"});     blockedCodeString.add(new String[]{"cvs"});     blockedCodeString.add(new String[]{"exec"});     blockedCodeString.add(new String[]{"ln"});     blockedCodeString.add(new String[]{"kill"});     blockedCodeString.add(new String[]{"rsync"});     blockedCodeString.add(new String[]{"lsof"});     blockedCodeString.add(new String[]{"crontab"});     blockedCodeString.add(new String[]{"libtool"});     blockedCodeString.add(new String[]{"automake"});     blockedCodeString.add(new String[]{"autoconf"});     blockedCodeString.add(new String[]{"make"});     blockedCodeString.add(new String[]{"gcc"});     blockedCodeString.add(new String[]{"cc"});   }   static boolean allMatch(String aim, String[] checker){     if(checker == null || checker.length < 1){       return false;     }else {       // by default, treat as match, every not match change it       for (String i : checker) {         if (!aim.matches(".*\\b" + i + "\\b.*")){           return false;         }       }       return true;     }   }   static String anyMatch(String aim, HashSet<String[]> all) throws Exception{     if(aim.contains("FUCK P&G")){       throw  new Exception("How do you know this ????");     } else {       for (String[] one : all) {         if (allMatch(aim, one)) {           StringBuilder sb = new StringBuilder();           for (String s : one) {             sb.append(s + " ");           }           return sb.toString();         }       }       throw new Exception("No one match");     }   }      //......此处是个public类   try{       String matchesStrings = anyMatch(st, blockedCodeString);       result = new InterpreterResult(Code.ERROR, "Contains dangerous code : " + matchesStrings);     }catch (Exception me){ // no match any       scheduler.submit(job);       while (!job.isTerminated()) {         synchronized (jobListener) {           try {             jobListener.wait(1000);           } catch (InterruptedException e) {             logger.info("Exception in RemoteInterpreterServer while interpret, jobListener.wait", e);           }         }       }       if (job.getStatus() == Status.ERROR) {         result = new InterpreterResult(Code.ERROR, Job.getStack(job.getException()));       } else {         result = (InterpreterResult) job.getReturn();         // in case of job abort in PENDING status, result can be null         if (result == null) {           result = new InterpreterResult(Code.KEEP_PREVIOUS_RESULT);         }       }     }   //......直到该public类结束

因为客户有deadline限制,所以快速定位源码位置的过程还是挺有意思的,比较紧张刺激,在这个以小时计算deadline压力下,什么intelliJ, Eclipse都不好使啊,就grep和vi最好用,从找到到改完,比客户定的deadline提前了好几个小时。



有关Hadoop运维记录系列(二十一)的更多相关文章

  1. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  2. ruby-on-rails - 使用一系列等级计算字母等级 - 2

    这里是Ruby新手。完成一些练习后碰壁了。练习:计算一系列成绩的字母等级创建一个方法get_grade来接受测试分数数组。数组中的每个分数应介于0和100之间,其中100是最大分数。计算平均分并将字母等级作为字符串返回,即“A”、“B”、“C”、“D”、“E”或“F”。我一直返回错误:avg.rb:1:syntaxerror,unexpectedtLBRACK,expecting')'defget_grade([100,90,80])^avg.rb:1:syntaxerror,unexpected')',expecting$end这是我目前所拥有的。我想坚持使用下面的方法或.join,

  3. ruby - Sinatra:运行 rspec 测试时记录噪音 - 2

    Sinatra新手;我正在运行一些rspec测试,但在日志中收到了一堆不需要的噪音。如何消除日志中过多的噪音?我仔细检查了环境是否设置为:test,这意味着记录器级别应设置为WARN而不是DEBUG。spec_helper:require"./app"require"sinatra"require"rspec"require"rack/test"require"database_cleaner"require"factory_girl"set:environment,:testFactoryGirl.definition_file_paths=%w{./factories./test/

  4. ruby-on-rails - Rails 5 Active Record 记录无效错误 - 2

    我有两个Rails模型,即Invoice和Invoice_details。一个Invoice_details属于Invoice,一个Invoice有多个Invoice_details。我无法使用accepts_nested_attributes_forinInvoice通过Invoice模型保存Invoice_details。我收到以下错误:(0.2ms)BEGIN(0.2ms)ROLLBACKCompleted422UnprocessableEntityin25ms(ActiveRecord:4.0ms)ActiveRecord::RecordInvalid(Validationfa

  5. 【鸿蒙应用开发系列】- 获取系统设备信息以及版本API兼容调用方式 - 2

    在应用开发中,有时候我们需要获取系统的设备信息,用于数据上报和行为分析。那在鸿蒙系统中,我们应该怎么去获取设备的系统信息呢,比如说获取手机的系统版本号、手机的制造商、手机型号等数据。1、获取方式这里分为两种情况,一种是设备信息的获取,一种是系统信息的获取。1.1、获取设备信息获取设备信息,鸿蒙的SDK包为我们提供了DeviceInfo类,通过该类的一些静态方法,可以获取设备信息,DeviceInfo类的包路径为:ohos.system.DeviceInfo.具体的方法如下:ModifierandTypeMethodDescriptionstatic StringgetAbiList​()Obt

  6. 阿里云RDS——产品系列概述 - 2

    基础版云数据库RDS的产品系列包括基础版、高可用版、集群版、三节点企业版,本文介绍基础版实例的相关信息。RDS基础版实例也称为单机版实例,只有单个数据库节点,计算与存储分离,性价比超高。说明RDS基础版实例只有一个数据库节点,没有备节点作为热备份,因此当该节点意外宕机或者执行重启实例、变更配置、版本升级等任务时,会出现较长时间的不可用。如果业务对数据库的可用性要求较高,不建议使用基础版实例,可选择其他系列(如高可用版),部分基础版实例也支持升级为高可用版。基础版与高可用版的对比拓扑图如下所示。优势 性能由于不提供备节点,主节点不会因为实时的数据库复制而产生额外的性能开销,因此基础版的性能相对于

  7. hadoop安装之保姆级教程(二)之YARN的配置 - 2

    1.1.1 YARN的介绍 为克服Hadoop1.0中HDFS和MapReduce存在的各种问题⽽提出的,针对Hadoop1.0中的MapReduce在扩展性和多框架⽀持⽅⾯的不⾜,提出了全新的资源管理框架YARN. ApacheYARN(YetanotherResourceNegotiator的缩写)是Hadoop集群的资源管理系统,负责为计算程序提供服务器计算资源,相当于⼀个分布式的操作系统平台,⽽MapReduce等计算程序则相当于运⾏于操作系统之上的应⽤程序。 YARN被引⼊Hadoop2,最初是为了改善MapReduce的实现,但是因为具有⾜够的通⽤性,同样可以⽀持其他的分布式计算模

  8. ruby-on-rails - 事件记录 : Select max of limit - 2

    我正在尝试将以下SQL查询转换为ActiveRecord,它正在融化我的大脑。deletefromtablewhereid有什么想法吗?我想做的是限制表中的行数。所以,我想删除少于最近10个条目的所有内容。编辑:通过结合以下几个答案找到了解决方案。Temperature.where('id这给我留下了最新的10个条目。 最佳答案 从您的SQL来看,您似乎想要从表中删除前10条记录。我相信到目前为止的大多数答案都会如此。这里有两个额外的选择:基于MurifoX的版本:Table.where(:id=>Table.order(:id).

  9. Ruby 守护进程导致 ActiveRecord 记录器 IOError - 2

    我目前正在用Ruby编写一个项目,它使用ActiveRecordgem进行数据库交互,我正在尝试使用ActiveRecord::Base.logger记录所有数据库事件具有以下代码的属性ActiveRecord::Base.logger=Logger.new(File.open('logs/database.log','a'))这适用于迁移等(出于某种原因似乎需要启用日志记录,因为它在禁用时会出现NilClass错误)但是当我尝试运行包含调用ActiveRecord对象的线程守护程序的项目时脚本失败并出现以下错误/System/Library/Frameworks/Ruby.frame

  10. ruby-on-rails - 在 Rails 中更高效地查找或创建多条记录 - 2

    我有一个应用需要发送用户事件邀请。当用户邀请friend(用户)参加事件时,如果尚不存在将用户连接到该事件的新记录,则会创建该记录。我的模型由用户、事件和events_user组成。classEventdefinvite(user_id,*args)user_id.eachdo|u|e=EventsUser.find_or_create_by_event_id_and_user_id(self.id,u)e.save!endendend用法Event.first.invite([1,2,3])我不认为以上是完成我的任务的最有效方法。我设想了一种方法,例如Model.find_or_cr

随机推荐