記一次開源工具某模組的基礎二次開發

  • 2019 年 11 月 26 日
  • 筆記

近日看到一些關於工具的文章,很多人對於寫工具類文章都是蜻蜓點水,寫搭建,寫基礎使用,但是基礎的開源工具在生產環境上的使用其實是比較困難的,有很多需要二次開發做到與生產環境適配,今天寫這篇文章的目的就在於開啟開源工具二次開發的思路,其中一個模組的二次開發很簡單,大家基本都能看懂,就以這篇簡單易懂的程式碼改動舉例。本次開源工具二次開發以cobra程式碼審計為例。

適用範圍:程式碼初學者、有一定python基礎與協議基礎

需求明確

首先要先明確自己的需求,我們的需求是在上線前做關聯性程式碼審計,我採用的是cobra,至於為什麼要使用cobra就不多說了,這是評估期間做的事情,文章主要寫二次開發。

顯示情況

我們的生產環境使用gitlab作為程式碼庫,僅允許ssh方式下拉程式碼,而不允許http公開拉程式碼,這麼做是為了安全,但是同樣的也對cobra的使用造成了一定的麻煩。因為基礎的cobra是沒有ssh下拉功能的,需要我們自己做二次開發

程式碼改動

首先在原基礎的cobra上我們做一個拉程式碼的測試

好像很叼的樣子,沒有漏洞,但是有層script提示沒有選擇目標

後台定位問題發現如下錯誤

一般出現這個問題不是分支錯誤就是路徑錯誤,反正是找不到文件的,那直接用git clone試試原路徑是否存在吧

500,詢問了gitlab負責人才知道是根本沒有開放http下拉程式碼的功能,統一使用ssh進行下拉。

那原基礎的cobra能直接用ssh拉程式碼嗎?試試看好了

提示請輸入URL,也就是輸入格式不對,那我們換一種方式輸入

還是一樣的提示,那看看後端是什麼情況吧

一切正常。

首先對問題進行定位

命令為find ./ -name 「*.py」|xargs grep 「Please input a valid URL」

命令意思為在本級目錄級下級目錄搜索內容為Please input a valid URL的py腳本

找到了api.py,讓我們進去看看這是什麼

果然只限定了http與https,那根據咱們的需求加上ssh吧

原程式碼:

  if re.match(r'http://|https://', t):                      arg = (t, formatter, output, rule, a_sid, is_del)                      producer(task=arg)                  else:                      return {"code": 1004, "msg": "Please input a valid URL"}              result = {                  'msg': 'Add scan job successfully.',                  'sid': a_sid,                  'total_target_num': len(target),              }          else:              if re.match(r'http://|https://', target):                  arg = (target, formatter, output, rule, a_sid, is_del)                  producer(task=arg)              else:                  return {"code": 1004, "msg": "Please input a valid URL"}

改動後程式碼:

        if re.match(r'http://|https://|ssh://', t):                      arg = (t, formatter, output, rule, a_sid, is_del)                      producer(task=arg)                  else:                      return {"code": 1004, "msg": "Please input a valid URL"}              result = {                  'msg': 'Add scan job successfully.',                  'sid': a_sid,                  'total_target_num': len(target),              }          else:              if re.match(r'http://|https://|ssh://', target):                  arg = (target, formatter, output, rule, a_sid, is_del)                  producer(task=arg)              else:                  return {"code": 1004, "msg": "Please input a valid URL"}

重新試一下吧

後台提示需要輸入root密碼

我的環境是做了[email protected]的免密推送,root用戶密碼我不知道啊,就算有許可權難道把密碼寫在配置文件里又安全嗎?明文密碼泄露的事情可是發生不少,於是繼續看程式碼找問題

find ./ -name "*.py" |xargs grep "git clone"

看他的推送方式是什麼

配置文件為./cobra/pickup.py

如果配置文件中沒有輸入用戶名或密碼,便是公開鏈接,直接clone,如果有用戶名密碼,則分割填入用戶名和密碼進行加密clone,如果這放在http協議中這個邏輯完全沒有問題,但是放在ssh下拉程式碼里,就會存在很大的邏輯問題了

邏輯問題在於ssh的免密鑰登錄不需要密碼,如果單純以用戶名密碼作為判斷依據那免密鑰的作用就為零了,為了適配免密鑰,實際上在程式碼中指定免密鑰的用戶即可,同時為保證其他基礎功能不遭受破壞,增加的功能應使用判斷前綴的方式進行程式碼改寫,具體如下:

原程式碼:

         if self.repo_username is None or self.repo_password is None:              # public repo              clone_address = self.repo_address          else:              # private repo              clone_address = self.repo_address.split('://')[0] + '://' + quote(self.repo_username) + ':' +                               quote(self.repo_password) + '@' + self.repo_address.split('://')[1]          # clone repo with username and password            # "http[s]://username:[email protected]/username/reponame"          # !!! if add password in the url, .git/config will log your url with password          cmd = 'git clone ' + clone_address + ' "' + self.repo_directory + '" -b ' + self.repo_branch 

改後程式碼:

     if self.repo_username is None or self.repo_password is None:              # public repo              if (self.repo_address.split('://')[0] == 'ssh'):                  clone_address = 'ssh://' + 'git@' +                   self.repo_address.split('://')[1]              else:              clone_address = self.repo_address          else:              # private repo              if (self.repo_address.split('://')[0] == 'ssh'):                  clone_address = 'ssh://' + 'git@' +                   self.repo_address.split('://')[1]              else:              clone_address = self.repo_address.split('://')[0] + '://' + quote(self.repo_username) + ':' +                               quote(self.repo_password) + '@' + self.repo_address.split('://')[1]          # clone repo with username and password          # "http[s]://username:[email protected]/username/reponame"          # !!! if add password in the url, .git/config will log your url with password          cmd = 'git clone ' + clone_address + ' "' + self.repo_directory + '" -b ' + self.repo_branch

增加前綴判斷,如果前綴為ssh,則統一使用通用用戶git進行ssh登錄程式碼拉取

進行測試

如此完成了一次很簡單的模組二次開發。

二次開發重要是需求與實現,將自己的需求完整的實現出來即可,不一定是框架意義上的開發才算二次開發,一定要明白自己需要的是什麼,程式碼邏輯是什麼,掌握好程式碼邏輯,二次開發也不算是很難的事情。

*本文原創作者:煜陽yuyang,本文屬於FreeBuf原創獎勵計劃,未經許可禁止轉載